Advertisement
Guest User

Untitled

a guest
Jul 8th, 2019
231
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 28.33 KB | None | 0 0
  1. <#
  2. .SYNOPSIS
  3. Name: VM_Image_Deployment.ps1
  4. Cross vCenter Clone Operation across different vCenter Servers.
  5. .DESCRIPTION
  6. This script creates and move a vCenter clone across two or multiple vCenter Servers which can either be part of the
  7. same or different SSO Domain. It clones the original VM with '-clone' at the end unless told otherwise. Moves the
  8. clone VM to the selected vCenter's cluster, datstore and assinged the designated portgroup as selected.
  9. .PARAMETER <Parameter_Name>
  10. credential
  11. vcname
  12. clusters
  13. datastores
  14. portgroups
  15. sourcevmname
  16. targetvmname
  17. .INPUTS
  18. None
  19. .OUTPUTS
  20. <Path>/VDIenvironments.csv
  21. .NOTES
  22. Version: 0.0.9
  23. Author: Carlhens Baptiste, David Lang
  24. Creation Date: 03/25/2019
  25.  
  26. Version History
  27. 0.0.1 2019-03-25 Initial script development.
  28. 0.0.2 2019-05-09 Switching environment input from csv to vCenter live data.
  29. 0.0.3 2019-05-10 Implement vCenter server login.
  30. 0.0.4 2019-06-19 Added clone vm function, error handling and bug fixes.
  31. 0.0.5 2019-06-20 Fixed windows size, text alignment, error handling and bug fixes.
  32. 0.0.6 2019-06-21 Implemented AD integration. Added more error handling.
  33. 0.0.7 2019-06-25 Fixed destination path to match source path for consistency.
  34. 0.0.8 2019-06-26 Fixed AD integration bug in script
  35. 0.0.9 2019-07-04 Added option to select a folder from the selected vCenter server folders.
  36.  
  37. .EXAMPLE
  38. powershell.exe -executionpolicy bypass -file "<Path>/VM_Image_Deployment.ps1"
  39. #>
  40.  
  41. #set global variable
  42. #import environment csv location path
  43. $filePath = "K:\Scripts\FileToRead"
  44. $vdiEnvironments = Import-Csv "$filePath\VDIenvironments.csv"
  45. $lstEnv = $vdiEnvironments.Env | Sort-Object -Unique
  46.  
  47. #XAML for GUI
  48. $inputXML = @"
  49. <Window x:Class="VM_Image_Deployment.MainWindow"
  50. xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
  51. xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
  52. xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
  53. xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
  54. xmlns:local="clr-namespace:VM_Image_Deployment"
  55. mc:Ignorable="d"
  56. Title="Image Deployment (Beta Ver 0.0.9)" ResizeMode="NoResize"
  57. Height="455"
  58. Width="1010" >
  59. <Grid Background="#FFEEEEEE">
  60. <Label Content="Environment"
  61. HorizontalAlignment="Left"
  62. VerticalAlignment="Top"
  63. Height="25"
  64. />
  65. <ComboBox x:Name="boxEnvironment"
  66. Margin="10,25,0,0"
  67. HorizontalAlignment="Left"
  68. VerticalAlignment="Top"
  69. Height="25"
  70. Width="190"
  71. />
  72. <Label Content="Source vCenter"
  73. Margin="0,50,0,0"
  74. HorizontalAlignment="Left"
  75. VerticalAlignment="Top"
  76. Height="25"
  77. />
  78. <ComboBox x:Name="boxSrcVCenter"
  79. Margin="10,75,0,0"
  80. HorizontalAlignment="Left"
  81. VerticalAlignment="Top"
  82. Height="25"
  83. Width="190"
  84. />
  85. <Label Content="Source VM"
  86. Margin="0,155,0,0"
  87. HorizontalAlignment="Left"
  88. VerticalAlignment="Top"
  89. Height="25"
  90. />
  91. <ListBox x:Name="listSrcVMs"
  92. Margin="10,180,0,0"
  93. HorizontalAlignment="Left"
  94. VerticalAlignment="Top"
  95. Height="150"
  96. Width="200"
  97. />
  98. <Label Content="Snapshot Description"
  99. Margin="0,331,0,0"
  100. HorizontalAlignment="Left"
  101. VerticalAlignment="Top"
  102. Height="25"
  103. />
  104. <TextBox x:Name="textSnapshotDescription"
  105. Text="Type a description of the target VM snapshot."
  106. TextWrapping="Wrap"
  107. Margin="10,357,0,0"
  108. HorizontalAlignment="Left"
  109. VerticalAlignment="Top"
  110. Height="54"
  111. Width="200"
  112. />
  113. <Label Content="Target vCenter servers to deploy image"
  114. Margin="220,0,0,0"
  115. HorizontalAlignment="Left"
  116. VerticalAlignment="Top"
  117. />
  118. <Grid HorizontalAlignment="Left"
  119. Background="#FFC8C8C8"
  120. Margin="230,30,0,0"
  121. VerticalAlignment="Top"
  122. Height="330"
  123. Width="755" >
  124. <Label Content="Target VCenters"
  125. Margin="0,0,0,0"
  126. HorizontalAlignment="Left"
  127. VerticalAlignment="Top"
  128. />
  129. <ListView x:Name="listTgtVCenters"
  130. SelectionMode="Multiple"
  131. Margin="10,25,0,0"
  132. HorizontalAlignment="Left"
  133. VerticalAlignment="Top"
  134. Height="295"
  135. Width="735" >
  136. <ListView.View>
  137. <GridView>
  138. <GridViewColumn Width="30">
  139. <GridViewColumn.CellTemplate>
  140. <DataTemplate>
  141. <CheckBox IsChecked="{Binding RelativeSource={
  142. RelativeSource AncestorType={x:Type ListViewItem}
  143. }, Path=IsSelected}"
  144. />
  145. </DataTemplate>
  146. </GridViewColumn.CellTemplate>
  147. </GridViewColumn>
  148. <GridViewColumn Header="Name"
  149. DisplayMemberBinding ="{Binding 'Name'}"
  150. Width="180"
  151. />
  152. <GridViewColumn Header="DC"
  153. DisplayMemberBinding ="{Binding 'Datacenter'}"
  154. Width="35"
  155. />
  156. <GridViewColumn Header="Target Cluster"
  157. Width="160" >
  158. <GridViewColumn.CellTemplate>
  159. <DataTemplate>
  160. <ComboBox ItemsSource="{Binding 'Clusters'}"
  161. SelectedItem="{Binding Path='TargetCluster', Mode=TwoWay}"
  162. Width="145"
  163. />
  164. </DataTemplate>
  165. </GridViewColumn.CellTemplate>
  166. </GridViewColumn>
  167. <GridViewColumn Header="Target Datastore"
  168. Width="160" >
  169. <GridViewColumn.CellTemplate>
  170. <DataTemplate>
  171. <ComboBox ItemsSource="{Binding 'Datastores'}"
  172. SelectedItem="{Binding Path='TargetDatastore', Mode=TwoWay}"
  173. Width="145"
  174. />
  175. </DataTemplate>
  176. </GridViewColumn.CellTemplate>
  177. </GridViewColumn>
  178. <GridViewColumn Header="Target PortGroup"
  179. Width="160" >
  180. <GridViewColumn.CellTemplate>
  181. <DataTemplate>
  182. <ComboBox ItemsSource="{Binding 'Portgroups'}"
  183. SelectedItem="{Binding Path='TargetPortgroup', Mode=TwoWay}"
  184. Width="145"
  185. />
  186. </DataTemplate>
  187. </GridViewColumn.CellTemplate>
  188. </GridViewColumn>
  189. </GridView>
  190. </ListView.View>
  191. </ListView>
  192. </Grid>
  193. <Button x:Name="buttonDeploy"
  194. Content="Deploy"
  195. Margin="0,0,19,17"
  196. HorizontalAlignment="Right"
  197. VerticalAlignment="Bottom"
  198. Width="75"
  199. />
  200. <Label Content="Source VM name"
  201. Margin="235,365,0,0"
  202. HorizontalAlignment="Left"
  203. VerticalAlignment="Top"
  204. />
  205. <TextBox x:Name="TextSourceVM"
  206. TextWrapping="Wrap"
  207. Margin="235,390,0,0"
  208. HorizontalAlignment="Left"
  209. VerticalAlignment="Top"
  210. Width="250"
  211. Height="20"
  212. IsEnabled = "False"
  213. />
  214. <Label Content="Target VM name"
  215. Margin="500,365,0,0"
  216. HorizontalAlignment="Left"
  217. VerticalAlignment="Top"
  218. />
  219. <TextBox x:Name="textTargetVM"
  220. TextWrapping="Wrap"
  221. Margin="500,390,0,0"
  222. HorizontalAlignment="Left"
  223. VerticalAlignment="Top"
  224. Width="250"
  225. Height="20"
  226. />
  227. <Label Content="Source vCenter Folder"
  228. Margin="0,102,0,0"
  229. HorizontalAlignment="Left"
  230. VerticalAlignment="Top"
  231. Height="25"
  232. />
  233. <ComboBox x:Name="boxSrcVCenterFolder"
  234. Margin="10,127,0,0"
  235. HorizontalAlignment="Left"
  236. VerticalAlignment="Top"
  237. Height="25"
  238. Width="190"
  239. />
  240. </Grid>
  241. </Window>
  242.  
  243. "@
  244.  
  245. ##begin function declaration
  246. function Get-FormVariables{
  247. Write-Host "Found the following interactive elements in the form:" -ForegroundColor Cyan
  248. Get-Variable WPF*
  249. }
  250.  
  251. function TestUserCredential
  252. {
  253. #Get user credentials
  254. $global:credential = Get-Credential -Message "Enter Your Credentials (Domain\Username)"
  255. if ($credential -eq $Null)
  256. {
  257. Write-Host "Please enter your username in the form of Domain\UserName and try again" -BackgroundColor Black -ForegroundColor Yellow
  258. Break
  259. }
  260.  
  261. #Parse provided user credentials
  262. $DomainNetBIOS = $credential.username.Split("{\}")[0]
  263. $UserName = $credential.username.Split("{\}")[1]
  264. $Password = $credential.GetNetworkCredential().password
  265.  
  266. Write-Host "`n"
  267. Write-Host "Checking Credentials for $DomainNetBIOS\$UserName" -BackgroundColor Black -ForegroundColor White
  268. Write-Host "***************************************"
  269.  
  270. If ($DomainNetBIOS -eq $Null -or $UserName -eq $Null)
  271. {
  272. Write-Host "Please enter your username in the form of Domain\UserName and try again" -BackgroundColor Black -ForegroundColor Yellow
  273. TestUserCredential
  274. }
  275. # Checks if the domain in question is reachable, and get the domain FQDN.
  276. Try
  277. {
  278. $DomainFQDN = (Get-ADDomain $DomainNetBIOS).DNSRoot
  279. }
  280. Catch
  281. {
  282. Write-Host "Error: Domain was not found: " $_.Exception.Message -BackgroundColor Black -ForegroundColor Red
  283. Write-Host "Please make sure the domain NetBios name is correct, and is reachable from this computer" -BackgroundColor Black -ForegroundColor Red
  284. Break
  285. }
  286.  
  287. #Checks user credentials against the domain
  288. $DomainObj = "LDAP://" + $DomainFQDN
  289. $DomainBind = New-Object System.DirectoryServices.DirectoryEntry($DomainObj,$UserName,$Password)
  290. $DomainName = $DomainBind.distinguishedName
  291.  
  292. If ($DomainName -eq $Null)
  293. {
  294. Write-Host "Domain $DomainFQDN was found: True" -BackgroundColor Black -ForegroundColor Green
  295.  
  296. $UserExist = Get-ADUser -Server $DomainFQDN -Properties LockedOut -Filter {sAMAccountName -eq $UserName}
  297. If ($UserExist -eq $Null)
  298. {
  299. Write-Host "Error: Username $Username does not exist in $DomainFQDN Domain." -BackgroundColor Black -ForegroundColor Red
  300. Write-Host "Validate username and re-enter your username in the for form of Domain\UserName and try again" -BackgroundColor Black -ForegroundColor Red
  301. TestUserCredential
  302. }
  303. Else
  304. {
  305. Write-Host "User exists in the domain: True" -BackgroundColor Black -ForegroundColor Green
  306.  
  307.  
  308. If ($UserExist.Enabled -eq "True")
  309. {
  310. Write-Host "User Enabled: " $UserExist.Enabled -BackgroundColor Black -ForegroundColor Green
  311. }
  312.  
  313. Else
  314. {
  315. Write-Host "User Enabled: " $UserExist.Enabled -BackgroundColor Black -ForegroundColor RED
  316. Write-Host "Enable the user account in Active Directory, Then check again" -BackgroundColor Black -ForegroundColor RED
  317. Break
  318. }
  319.  
  320. If ($UserExist.LockedOut -eq "True")
  321. {
  322. Write-Host "User Locked: " $UserExist.LockedOut -BackgroundColor Black -ForegroundColor Red
  323. Write-Host "Unlock the User Account in Active Directory, Then check again..." -BackgroundColor Black -ForegroundColor RED
  324. Break
  325. }
  326. Else
  327. {
  328. Write-Host "User Locked: " $UserExist.LockedOut -BackgroundColor Black -ForegroundColor Green
  329. }
  330. }
  331.  
  332. Write-Host "Authentication failed for $DomainNetBIOS\$UserName with the provided password." -BackgroundColor Black -ForegroundColor Red
  333. Write-Host "Please confirm the password, and try again..." -BackgroundColor Black -ForegroundColor Red
  334.  
  335. $global:credential = $Null
  336.  
  337. Break
  338. }
  339.  
  340. Else
  341. {
  342. Write-Host "SUCCESS: The account $Username successfully authenticated against the domain: $DomainFQDN" -BackgroundColor Black -ForegroundColor Green
  343. Write-host "`n"
  344. }
  345. }
  346.  
  347. function xNew-VM{
  348. param (
  349. [string]$sourceVCName,
  350. [string]$sourceClusterName,
  351. [string]$sourceFolderName,
  352. [string]$sourceDatastoreName,
  353. [string]$sourceVMName,
  354. [string]$destVCName,
  355. [string]$destClusterName,
  356. [string]$destFolderName,
  357. [string]$destDatastoreName,
  358. [string]$destPortgroupName,
  359. [string]$destVMName
  360. )
  361.  
  362. $location = 'vm'
  363. $testfolder = Get-Folder -Server $destVCName -Name $destFolderName -ErrorAction SilentlyContinue
  364. if (!($testfolder)){
  365. Write-host "`n"
  366. Write-warning "Folder $($destFolderName) does not exist in $($destVCName)"
  367. Write-warning "Folder $($destFolderName) will be created on $($destVCName) to complete task"
  368. try {
  369. New-Folder -Server $destVCName -Name $destFolderName -Location $location -ErrorAction Stop
  370. if ($? -eq $false) {throw $error[0].exception}
  371. }
  372. catch [Exception]
  373. {
  374. Write-host "`n"
  375. Write-Error "Unable to create folder $($destFolderName) in $($destVCName)"
  376. Write-Host "Ending Script"
  377. Break
  378. }
  379. }
  380.  
  381. #Destination server variables
  382. $destHost = Get-Cluster -Server $destVCName -Name $destClusterName | Get-VMHost | `
  383. Where {$_.ConnectionState -eq "Connected"} | Get-Random -Count 1
  384. $destFolder = Get-Folder -Server $destVCName -Name $destFolderName
  385. $destDatastore = Get-Datastore -Server $destVCName -Name $destDatastoreName
  386. $destPorgroup = Get-VDPortgroup -Server $destVCName -Name $destPortgroupName
  387.  
  388.  
  389. #New VM Variables
  390. $cloneVM = Get-VM -Name $sourceVMName -Server $sourceVCName
  391. $cloneVMDatastore = Get-Datastore -Server $sourceVCName -Name $sourceDatastoreName
  392. $cloneVMLocation = Get-Folder $sourceFolderName -Type VM -Server $sourceVCName
  393. $cloneVMResourcePool = Get-Cluster $sourceClusterName -Server $sourceVCName
  394.  
  395.  
  396. #Clone the VM to be moved in the source vCenter
  397. Write-Host "`nCloning $($cloneVM)" -ForegroundColor DarkCyan
  398. try
  399. {
  400. New-VM -Server $sourceVCName -Name $destVMName -VM $cloneVM -Datastore $cloneVMDatastore -Location $cloneVMLocation `
  401. -DiskStorageFormat Thin -ResourcePool $cloneVMResourcePool -WarningAction SilentlyContinue
  402. }
  403. catch
  404. {
  405. Write-Error -Message $($_.Exception.Message)
  406. Break
  407. }
  408.  
  409. #Move the VM to the destination vCenter
  410. Write-Host "Relocating $($cloneVM) to vCenter $($destVCName)" -ForegroundColor DarkCyan
  411. try
  412. {
  413. Move-VM -Server $sourceVCName -VM $destVMName -VMotionPriority High -Destination $destHost -Datastore $destDatastore `
  414. -InventoryLocation $destFolder -Portgroup $destPorgroup -Confirm:$false -WarningAction SilentlyContinue
  415. }
  416. catch
  417. {
  418. Write-Error -Message $($_.Exception.Message)
  419. Break
  420. }
  421.  
  422. }
  423. ##end function declaration
  424.  
  425. #validate if user credentials are valid or older than 3 hours
  426. if (!($credential)){
  427. TestUserCredential
  428. }
  429.  
  430.  
  431. #load XAML into Form GUI
  432. $inputXML = $inputXML -replace 'mc:Ignorable="d"','' -replace "x:N",'N' -replace '^<Win.*', '<Window'
  433. [xml]$xaml = $inputXML
  434. $reader=(New-Object System.Xml.XmlNodeReader $xaml)
  435. $form=[Windows.Markup.XamlReader]::Load( $reader )
  436.  
  437. #bind XAML elements to PS variables starting with "WPF"
  438. $xaml.SelectNodes("//*[@Name]") |
  439. foreach-object {
  440. "Trying item $($_.Name)"
  441. try {Set-Variable -Name "WPF$($_.Name)" -Value $form.FindName($_.Name) -ErrorAction Stop}
  442. catch {Throw}
  443. }
  444.  
  445.  
  446. Get-FormVariables
  447.  
  448. #load "Environments" into box
  449. $lstEnv | ForEach-Object {$wpFBoxEnvironment.Items.Add($_)}
  450.  
  451. #event: when Environment is selected
  452. $wpFBoxEnvironment.Add_DropDownClosed({
  453. #empty VCenters inside form
  454. $wpFBoxSrcVCenter.Items.Clear()
  455. $wpFListTgtVCenters.Items.Clear()
  456. #empty Source VMs inside form
  457. $wpFListSrcVMs.Items.Clear()
  458. #empty vCenters folder inside form
  459. $wpFBoxSrcVCenterFolder.Items.Clear()
  460. #validate VI servers connetion and connect if session doesn't exist
  461. $VServers = $vdiEnvironments |
  462. Where-Object Env -like $wpFBoxEnvironment.Text
  463.  
  464. #notify use to wait for vCenter server login
  465. Write-Host "Authenticating to all $($wpFBoxEnvironment.Text) servers. Please wait..." -ForegroundColor Cyan
  466.  
  467. ForEach ($VServer in $VServers){
  468. $sessionID = ($global:DefaultVIServers | Where-Object -FilterScript {$_.Name -like $VServer.Name}).sessionId
  469. if ($sessionID) {Connect-VIServer -Server $VServer.Name -Session $sessionID}
  470. if ($credential){
  471. try
  472. {
  473. Connect-VIServer -Server $VServer.Name -Credential $credential -ErrorAction Stop
  474. if ($? -eq $false) {throw $error[0].exception}
  475. }
  476. catch [Exception]
  477. {
  478.  
  479. Write-Warning "$($VServer.Name) is unavailable. See error information for more details."
  480. Write-Host $_
  481. }
  482. }
  483. }
  484.  
  485.  
  486. $clusters = Get-Cluster | Select-Object Name, Uid
  487. $clusters | ForEach-Object {
  488. $_ | Add-Member -MemberType NoteProperty -Name VCName -Value $_.Uid.split('@')[1].split(':')[0]
  489. }
  490.  
  491. $datastores = Get-Datastore | Select-Object -Property Name, DatastoreBrowserPath, FreeSpaceMB, CapacityMB
  492. $datastores | ForEach-Object {
  493. $_ |
  494. Add-Member -MemberType NoteProperty `
  495. -Name VCName -Value $_.DatastoreBrowserPath.split('\')[1].replace('@443','')
  496. $_.FreeSpaceMB = [int]$_.FreeSpaceMB
  497. $_.CapacityMB = [int]$_.CapacityMB
  498. }
  499.  
  500. $portgroups = Get-VDPortgroup | Select-Object VlanConfiguration, Name, NumPorts, Uid | ? VlanConfiguration -notlike "*0-4094*"
  501. $portgroups | ForEach-Object {
  502. $_ | Add-Member -MemberType NoteProperty -Name VCName -Value $_.Uid.split('@')[1].split(':')[0]
  503. $_.NumPorts = [int]$_.NumPorts
  504. }
  505.  
  506.  
  507. $ErrorActionPreference = "SilentlyContinue"
  508. $vCenters = @()
  509. Foreach ($vCenter in $VDIEnvironments) {
  510. $vCenter |
  511. Add-Member -MemberType NoteProperty -Name TargetCluster -Value (
  512. $clusters | ? VCName -like $vCenter.Name
  513. )[0].Name -Force
  514. $vCenter |
  515. Add-Member -MemberType NoteProperty -Name Clusters -Value $(
  516. $clusters | ? VCName -like $vCenter.Name
  517. ).Name -Force
  518. $vCenter |
  519. Add-Member -MemberType NoteProperty -Name TargetDatastore -Value $(
  520. $datastores | ? VCName -like $vCenter.Name | Sort-Object -Descending FreeSpaceMB
  521. )[0].Name -Force
  522. $vCenter |
  523. Add-Member -MemberType NoteProperty -Name Datastores -Value $(
  524. $datastores | ? VCName -like $vCenter.Name
  525. ).Name -Force
  526. $vCenter |
  527. Add-Member -MemberType NoteProperty -Name TargetPortgroup -Value (
  528. $portgroups | ? VCName -like $vCenter.Name | Sort-Object -Descending NumPorts
  529. )[0].Name -Force
  530. $vCenter |
  531. Add-Member -MemberType NoteProperty -Name Portgroups -Value $(
  532. $portgroups | ? VCName -like $vCenter.Name
  533. ).Name -Force
  534.  
  535. $vCenters += $vCenter
  536. }
  537. $ErrorActionPreference = "Continue"
  538.  
  539. #fill VCenters inside form from selected Environment
  540. $SelectedVCenters = $VCenters |
  541. Where-Object Env -like $WPFboxEnvironment.Text |
  542. Where-Object Datastores -ne $Null
  543. $SelectedVCenters | ForEach-Object {
  544. $WPFboxSrcVCenter.Items.Add($_.Name)
  545. $WPFlistTgtVCenters.Items.Add($_)
  546. $WPFlistTgtVCenters.SelectedItems.Add($_)
  547. }
  548. })
  549.  
  550. #event: when Source VCenter is selected
  551. $wpFBoxSrcVCenter.Add_DropDownClosed({
  552. #empty vCenters folder inside form
  553. $wpFBoxSrcVCenterFolder.Items.Clear()
  554. #empty Source VMs inside form
  555. $wpFListSrcVMs.Items.Clear()
  556.  
  557. $srcVCFolders = Get-Folder -Server $wpFBoxSrcVCenter.Text -Type VM | Select-Object Name
  558.  
  559. #fill vCenter folder inside form
  560. $srcVCFolders | ForEach-Object {
  561. $wpFBoxSrcVCenterFolder.Items.Add($_.Name)
  562. }
  563.  
  564. })
  565.  
  566. #event: when Source vCenter Folder is selected
  567. $wpFBoxSrcVCenterFolder.Add_DropDownClosed({
  568. #empty Source VMs inside form
  569. $wpFListSrcVMs.Items.Clear()
  570.  
  571. #get VMs from selected VCenter
  572. if ($global:DefaultVIServers | Where-Object -FilterScript {$_.Name -like $wpFBoxSrcVCenter.Text}){
  573. $srcVMs = Get-VM -Server $wpFBoxSrcVCenter.Text -Location $wpFBoxSrcVCenterFolder.text | Select-Object Name
  574. #fill Source VMs inside form
  575. $srcVMs | ForEach-Object {
  576. $wpFListSrcVMs.Items.Add($_.Name)
  577. }
  578. }
  579.  
  580. })
  581.  
  582. #event: when Source VM is selected
  583. $wpFListSrcVMs.Add_SelectionChanged({
  584. $wpFTextSourceVM.Text = $wpFListSrcVMs.SelectedItem
  585. $wpFtextTargetVM.Text = $wpFListSrcVMs.SelectedItem + '-clone'
  586. })
  587.  
  588.  
  589. #event: add click handler
  590. $wpFButtonDeploy.add_Click{
  591. Clear-Host
  592. Write-Host "Source Environment:"$wpFBoxEnvironment.Text
  593. Write-Host "Source VCenter:"$wpFBoxSrcVCenter.Text
  594. Write-Host "Source VM:"$wpFListSrcVMs.SelectedItem
  595. Write-Host "`nCDC Target VM name:"$wpFTextSourceVM.Text"`
  596. `tSDC Target VM name:"$wpFTextTargetVM.Text
  597. Write-Host "Snapshot Description:"$wpFTextSnapshotDescription.Text
  598. Write-Host "`nTarget VCenters:"
  599. $TargetVCs = $wpFListTgtVCenters.SelectedItems | Sort-Object Name
  600. Write-Host -ForegroundColor Black -BackgroundColor White `
  601. "`tVC Name".PadRight(25) `
  602. "`tDatacenter".PadRight(10) `
  603. "`tTarget Cluster".PadRight(40) `
  604. "`tTarget Datastore".PadRight(40) `
  605. "`tTarget Portgroup".PadRight(40) `t
  606.  
  607. Foreach ($TargetVC in $TargetVCs) {
  608. Write-Host -ForegroundColor White -BackgroundColor DarkGray `t `
  609. $TargetVC.Name.PadRight(25) `
  610. $TargetVC.Datacenter.PadRight(15) `
  611. $TargetVC.TargetCluster.PadRight(40) `
  612. $TargetVC.TargetDatastore.PadRight(40) `
  613. $TargetVC.TargetPortgroup.PadRight(40)
  614.  
  615. }
  616. #clone vm to each vcenters and snapshot
  617. Foreach ($TargetVC in $TargetVCs) {
  618. if ($TargetVC -match $wpFBoxSrcVCenter.Text){
  619. continue;
  620. }
  621. #function to clone and move VM to all VI servers other than source
  622. #snapshot the clone
  623.  
  624. $objVC = New-Object PSObject -Property @{
  625. SourceVCName = $wpFBoxSrcVCenter.Text
  626. SourceVMName = $wpFListSrcVMs.SelectedItem
  627. SourceClusterName = (Get-Cluster -VM $wpFListSrcVMs.SelectedItem -Server $wpFBoxSrcVCenter.Text).Name
  628. SourceFolderName = $wpFBoxSrcVCenterFolder.Text
  629. SourceDatastoreName = (Get-DataStore -VM $wpFListSrcVMs.SelectedItem -Server $wpFBoxSrcVCenter.Text).Name
  630. SourceParentSnapExist = (Get-Snapshot -vm $wpFListSrcVMs.SelectedItem -Server $wpFBoxSrcVCenter.Text).IsCurrent
  631. DestVCName = $TargetVC.Name
  632. DestVMName = $wpFtextTargetVM.Text
  633. DestClusterName = $TargetVC.TargetCluster
  634. DestFolderName = $wpFBoxSrcVCenterFolder.Text
  635. DestDatastoreName = $TargetVC.TargetDatastore
  636. DestPortgroupName = $TargetVC.TargetPortgroup
  637. SnapShotName = (Get-Date -Format s)
  638. SnapShotDescription = $wpFTextSnapshotDescription.Text
  639. }
  640.  
  641. #clone and migrate the VM to target vCenter servers
  642. xNew-VM -sourceVCName $objVC.SourceVCName -sourceClusterName $objVC.SourceClusterName `
  643. -sourceFolderName $objVC.SourceFolderName -sourceDatastoreName $objVC.SourceDatastoreName `
  644. -sourceVMName $objVC.SourceVMName -destVCName $objVC.DestVCName -destClusterName $objVC.DestClusterName `
  645. -destFolderName $objVC.DestFolderName -destDatastoreName $objVC.DestDatastoreName `
  646. -destPortgroupName $objVC.DestPortgroupName -destVMName $objVC.DestVMName
  647.  
  648. #snapshot the target clone after successful migration
  649. Write-host "Taking snashopt of the destination VM" -ForegroundColor DarkCyan
  650.  
  651. try {
  652. New-Snapshot -Server $objVC.DestVCName -VM $objVC.DestVMName -Name $objVC.SnapShotName -Description $objVC.SnapShotDescription
  653. }
  654. catch
  655. {
  656. Write-Host "An error occured:"
  657. Write-Host $_
  658. }
  659. }
  660.  
  661. #rename the source vm if the environment is production
  662. #snapshot source vm
  663. Write-host "`nTaking snashopt of the source VM" -ForegroundColor DarkCyan
  664. if (!($objVC.SourceParentSnapExist)){
  665. try {
  666.  
  667. New-Snapshot -Server $objVC.SourceVCName -VM $objVC.SourceVMName -Name $objVC.SnapShotName -Description $objVC.SnapShotDescription
  668. }
  669. catch
  670. {
  671. Write-Host "An error occured:"
  672. Write-Host $_
  673. }
  674. }else {
  675. Write-host "`A snapshot already exist. Skipping this task." -ForegroundColor DarkCyan -BackgroundColor White
  676. }
  677.  
  678. Write-host "`n"
  679. Write-host "Task complete. VM has been deployed to all available vCenter servers." -ForegroundColor DarkGray
  680. }
  681.  
  682. #show window
  683. $form.ShowDialog() | Out-Null
  684.  
  685. #on window close
  686. $wpFListTgtVCenters.SelectedItems |
  687. Sort-Object Name |
  688. Select-Object Env, Name, Datacenter, TargetCluster, TargetDatastore, TargetPortgroup |
  689. Format-Table -AutoSize
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement