Invoke PowerShell Scripts using vRO, Part-1
In this blogpost i would like to share my experience of integrating vRealize Automation with vRealize Orchestrator and how seamless it is to create a custom workflow which can invoke powershell script from vRO powershell host.
In part one of this blog we would take deep dive into the crux of the solution which is vRO which allows you to create customized workflows
As we all know PowerShell is one of the most admin friendly and integrates with almost every product we have in market now.
With this integration we can create a custom self service portal using vRA and provide multitudes of service offerings which use powershell script’s and vRO powershell host in the background to perform an activity.
So lets get started with the details on the solution, Invoke PowerShell Scripts from VRO .
Prerequisites involve, a powershell host added to the vRO appliance, you should be able to see a green check-mark once the workflow successfully completes its execution. You can follow these excellent blog posts on how to add a powershell host if you have not done it yet.
Spas Kaloferov’s Blog – Adding vCO Powershell Host with account other than the default domain administrator account
DefinIT – Configuring a vRO/vCAC PowerShell host with Basic Authentication
Also if you are using an external orchestra-tor server make sure that you have configured it to be used with v Realize Automation.
Once all the pre-requisites are met, lets start with the integration script and workflows.
For my testing purpose i would be illustrating the integration by creating a workflow which invokes a powershell script which would basically uses the PowerCLI cmdlets to create a test VM based on the form input provided either through vra or vro.
Log into the vRO console, and change the view to design mode. and create a new workflow called as “Create_Test_VM”.
Next Click on the edit (pencil icon) workflow button present on the top end of the screen to edit the workflow.
Drag and drop the scrip-table task and Invoke an External script schema integration components into the design whiteboard in schema view.
Next lets start configuring each of these elements.
Click on the “Inputs” tab and define the parameters which would be fed into the powershell script.
Note that the password to connect to the vcenter can be declared a “Secure String” type which allows you to mask out the password with “******” in the input form :), now that’s really cool without the use of any custom programming.
Once we define the input parameters, head over to the output tab, and create a new parameter called as “scriptarg” and move it as an attribute, this attribute will contain the format of how we pass the parameters to the powershell script.
Next move to the schema view and edit the properties of the “Scriptable Task” schema object.
Click on the “Bind to workflow parameter button” and select the input parameters we defined in the previous step.
Once you select all the parameters, perform the similar step on the output tab and select the bind the output to the attribute “scriptarg”
Next click on the visual binding tab and make sure that you see a similar binding structure as depicted below.
Next move on to the scripting tab and define the exact arguments which would be passed on to the powershell script.
Note that you would need to take care of spaces between the parameters or else the powershell script would not be able to understand the parameter format.
Below script block represents the exact format of the parameters with spaces in b/w
scriptarg = "-vcenterserver" + " " + vcenterserver + " " + "-username" + " " + username + " " + "-password" + " " + password + " " + "-vmname" + " " + vmname + " " + "-vpgroup" + vpgroup;
Next edit the properties of the “Invoke an external script” schema object and select “scriptarg” as the argument to the powershell script.
Click on save and close the workflow.
Woaahh!, now that was a huge set of steps, but i hope that my screen-capture based step by step procedure helped you out a lot.
Next lets test the workflow , click on run, and feed in the required parameters and click on submit to Invoke PowerShell Scripts using VRO .
Note that you need to install PowerCLI on the powershell host, also the script file during my test was placed at c:\users location in the powershell host
Now if you log into your vcenter server you would be greeted with your VM cloning task in action 🙂
Here’s the VM Cloning script which gets called.
param( $vmname, $vcenterserver, $username, $password, $vpgroup ) Add-PSSnapin VMware.VimAutomation.Core $secpasswd = ConvertTo-SecureString $password -AsPlainText -Force $vccredential = New-Object System.Management.Automation.PSCredential ($username, $secpasswd) Connect-VIServer $vcenterserver -Credential $vccredential | Out-Null Get-OSCustomizationSpec -Type NonPersistent | Remove-OSCustomizationSpec -Confirm:$false $Spec = Get-OSCustomizationSpec 'Win2k12R2OSSpec' | New-OSCustomizationSpec -Name 'PRSpec' -Type NonPersistent $Spec = Get-OSCustomizationNicMapping -Spec 'PRSpec' | Set-OSCustomizationNicMapping -IPmode UseStaticIP -IpAddress '<your parameters here>' -SubnetMask '<your parameters here>' -DefaultGateway '<your parameters here>' -Dns '<your parameters here>' $osCust = Get-OSCustomizationSpec -Name 'PRSpec' $clonetask = New-VM -template WIN2K12R2-TEMPLATE -vmhost '<your parameters here>' -name $vmname -runasync -Datastore '<your parameters here>' -OSCustomizationSpec $osCust Get-Task -Id $clonetask.ID | Wait-Task start-vm $vmname | wait-tools Start-Sleep 5 # Connect and assign network name Get-VM $VMname | Get-NetworkAdapter | Set-NetworkAdapter -Connected:$true -StartConnected:$true -vpgroup $vpgroup -Confirm:$false ##### Wait for the VM to be powered on ##### $VM = Get-VM -Name $vmname While ($vm.ExtensionData.Runtime.PowerState -ne 'poweredOn') { Start-Sleep -Seconds 1 $vm.ExtensionData.UpdateViewData('Runtime.PowerState') } function WaitVM-Customization { [CmdletBinding()] param( # VMs to monitor for OS customization completion [Parameter(Mandatory=$true)] [ValidateNotNullOrEmpty()] [VMware.VimAutomation.ViCore.Types.V1.Inventory.VirtualMachine[]] $vm, # timeout in seconds to wait [int] $timeoutSeconds = 600 ) <# .SYNOPSIS Waits customization process for list virtual machines to completes. .DESCRIPTION Waits customization process for list virtual machines to completes. The script returns if customization process ends for all virtual machines or if the specified timeout elapses. The script returns PSObject for each specified VM. The output object has VM and CustomizationStatus properties. .EXAMPLE $vm = 1..10 | foreach { New-VM -Template WindowsXPTemplate -OSCustomizationSpec WindowsXPCustomizaionSpec -Name "winxp-$_" } .\WaitVmCustomization.ps1 -vmList $vm -timeoutSeconds 600 .NOTES The script is based on sveral vCenter events. * VmStarting event - this event is posted on power on operation * CustomizationStartedEvent event - this event is posted for VM when customiztion has started * CustomizationSucceeded event - this event is posted for VM when customization has successfully completed * CustomizationFailed - this event is posted for VM when customization has failed Possible CustomizationStatus values are: * "VmNotStarted" - if it was not found VmStarting event for specific VM. * "CustomizationNotStarted" - if it was not found CustomizationStarterdEvent for specific VM. * "CustomizationStarted" - CustomizationStartedEvent was found, but Succeeded or Failed event were not found * "CustomizationSucceeded" - CustomizationSucceeded event was found for this VM * "CustomizationFailed" - CustomizationFailed event wass found for this VM #> # constants for status $STATUS_VM_NOT_STARTED = "VmNotStarted" $STATUS_CUSTOMIZATION_NOT_STARTED = "CustomizationNotStarted" $STATUS_STARTED = "CustomizationStarted" $STATUS_SUCCEEDED = "CustomizationSucceeded" $STATUS_FAILED = "CustomizationFailed" $STATUS_NOT_COMPLETED_LIST = @( $STATUS_CUSTOMIZATION_NOT_STARTED, $STATUS_STARTED ) # constants for event types $EVENT_TYPE_CUSTOMIZATION_STARTED = "VMware.Vim.CustomizationStartedEvent" $EVENT_TYPE_CUSTOMIZATION_SUCCEEDED = "VMware.Vim.CustomizationSucceeded" $EVENT_TYPE_CUSTOMIZATION_FAILED = "VMware.Vim.CustomizationFailed" $EVENT_TYPE_VM_START = "VMware.Vim.VmStartingEvent" # seconds to sleep before next loop iteration $WAIT_INTERVAL_SECONDS = 15 function main($vm, $timeoutSeconds) { # the moment in which the script has started # the maximum time to wait is measured from this moment $startTime = Get-Date # we will check for "start vm" events 5 minutes before current moment $startTimeEventFilter = $startTime.AddMinutes(-5) # initializing list of helper objects # each object holds VM, customization status and the last VmStarting event $vmDescriptors = New-Object System.Collections.ArrayList foreach($vm in $vm) { Write-Host "Start monitoring customization process for vm '$vm'" $obj = "" | select VM,CustomizationStatus,StartVMEvent $obj.VM = $vm # getting all events for the $vm, # filter them by type, # sort them by CreatedTime, # get the last one $obj.StartVMEvent = Get-VIEvent -Entity $vm -Start $startTimeEventFilter | ` where { $_ -is $EVENT_TYPE_VM_START } | Sort CreatedTime | Select -Last 1 if (-not $obj.StartVMEvent) { $obj.CustomizationStatus = $STATUS_VM_NOT_STARTED } else { $obj.CustomizationStatus = $STATUS_CUSTOMIZATION_NOT_STARTED } [void]($vmDescriptors.Add($obj)) } # declaring script block which will evaulate whether # to continue waiting for customization status update $shouldContinue = { # is there more virtual machines to wait for customization status update # we should wait for VMs with status $STATUS_STARTED or $STATUS_CUSTOMIZATION_NOT_STARTED $notCompletedVms = $vmDescriptors | ` where { $STATUS_NOT_COMPLETED_LIST -contains $_.CustomizationStatus } # evaulating the time that has elapsed since the script is running $currentTime = Get-Date $timeElapsed = $currentTime - $startTime $timoutNotElapsed = ($timeElapsed.TotalSeconds -lt $timeoutSeconds) # returns $true if there are more virtual machines to monitor # and the timeout is not elapsed return ( ($notCompletedVms -ne $null) -and ($timoutNotElapsed) ) } while (& $shouldContinue) { foreach ($vmItem in $vmDescriptors) { $vmName = $vmItem.VM.Name switch ($vmItem.CustomizationStatus) { $STATUS_CUSTOMIZATION_NOT_STARTED { # we should check for customization started event $vmEvents = Get-VIEvent -Entity $vmItem.VM -Start $vmItem.StartVMEvent.CreatedTime $startEvent = $vmEvents | where { $_ -is $EVENT_TYPE_CUSTOMIZATION_STARTED } if ($startEvent) { $vmItem.CustomizationStatus = $STATUS_STARTED Write-Host "VI Event Generated - Customization for VM '$vmName' has started" -ForegroundColor Yellow -BackgroundColor Black } break; } $STATUS_STARTED { # we should check for customization succeeded or failed event $vmEvents = Get-VIEvent -Entity $vmItem.VM -Start $vmItem.StartVMEvent.CreatedTime $succeedEvent = $vmEvents | where { $_ -is $EVENT_TYPE_CUSTOMIZATION_SUCCEEDED } $failedEvent = $vmEvents | where { $_ -is $EVENT_TYPE_CUSTOMIZATION_FAILED } if ($succeedEvent) { $vmItem.CustomizationStatus = $STATUS_SUCCEEDED Write-Host "VI Event Generated - Customization for VM '$vmName' has successfully completed" -ForegroundColor Green -BackgroundColor Black } if ($failedEvent) { $vmItem.CustomizationStatus = $STATUS_FAILED Write-Host "Customization for VM '$vmName' has failed" } break; } default { # in all other cases there is nothing to do # $STATUS_VM_NOT_STARTED -> if VM is not started, there's no point to look for customization events # $STATUS_SUCCEEDED -> customization is already succeeded # $STATUS_FAILED -> customization break; } } # enf of switch } # end of the freach loop Write-Host "Awaiting OS Customization VI Event, Sleeping for $WAIT_INTERVAL_SECONDS seconds" -BackgroundColor Black Sleep $WAIT_INTERVAL_SECONDS } # end of while loop # preparing result, without the helper column StartVMEvent $result = $vmDescriptors | select VM,CustomizationStatus return $result } main $vm $timeoutSeconds } WaitVM-Customization -vm $vm
I hope you enjoyed this blogpost on “Invoke PowerShell Scripts using VRO” and found the information useful, there is no limit to the endless possibilities we can attain with powershell an powercli in hand !!
Stay tuned for my next post where i would show how easy it is to integrate this solution with vRealize automation and offer this service to end users via a self service portal.
Do Check out my other posts on VRO, VRA and PowerShell
Pingback: Invoke PowerShell Scripts using vRO 7.0. Part - 2
thanks, great post, got it all set up! The only thing that’s off is that password isn’t passed to the script. Any idea why this is failing?
it should work as normal, the only difference is that its not visible to the user, rest all remains the same as the other set of parameters
Oops was related to my password, which started with @. It’s working now!
great to know that it was helpful for you
Thank you for posting this! Great Job.
Pingback: AutoScale vSphere Workloads with vRA and NetScaler NITRO API's
This is great. IS there a way I can add the following 3 items in to this script:
1. Rename the windows machine
2. Set the IP, Subnet mask and default gateway (From user input)
3. Join it to the domain
Hello Vinit,
I have a quick question , do we need to enable credSSP on powershell for delegating AD permissions.
Hello Vinit,
I have a quick question , do we need to enable credSSP on powershell host for delegating AD permissions.
do you know how i can get the results back from Powercli execution back to vRO? Seems i don’t get the results