This commit is contained in:
Jase McCarty
2018-12-10 13:37:31 -07:00
155 changed files with 30993 additions and 747 deletions

View File

@@ -32,13 +32,13 @@
If a -LocationType is not chosen, the function will default to FTP.
The destination location for a backup must be an empty folder (easiest to use the get-date cmdlet in the location)
-ShowProgress will give you a progressbar as well as updates in the console
-SeatBackup will only backup the config whereas -Fullbackup grabs the historical data as well
-CommonBackup will only backup the config whereas -Fullbackup grabs the historical data as well
#>
param (
[Parameter(ParameterSetName=FullBackup)]
[switch]$FullBackup,
[Parameter(ParameterSetName=SeatBackup)]
[switch]$SeatBackup,
[Parameter(ParameterSetName=CommonBackup)]
[switch]$CommonBackup,
[ValidateSet('FTPS', 'HTTP', 'SCP', 'HTTPS', 'FTP')]
$LocationType = "FTP",
$Location,
@@ -50,13 +50,14 @@
)
Begin {
if (!($global:DefaultCisServers)){
Add-Type -Assembly System.Windows.Forms
[System.Windows.Forms.MessageBox]::Show("It appears you have not created a connection to the CisServer. You will now be prompted to enter your vCenter credentials to continue" , "Connect to CisServer") | out-null
$Connection = Connect-CisServer $global:DefaultVIServer
} else {
$Connection = $global:DefaultCisServers
}
if ($FullBackup) {$parts = @("common","seat")}
if ($SeatBackup) {$parts = @("seat")}
if ($CommonBackup) {$parts = @("common")}
}
Process{
$BackupAPI = Get-CisService com.vmware.appliance.recovery.backup.job
@@ -72,7 +73,7 @@
$BackupJob = $BackupAPI.create($CreateSpec)
}
catch {
Write-Error $Error[0].exception.Message
throw $_.Exception.Message
}
@@ -84,6 +85,7 @@
start-sleep -seconds 5
} until ($BackupAPI.get("$($BackupJob.ID)").progress -eq 100 -or $BackupAPI.get("$($BackupJob.ID)").state -ne "INPROGRESS")
Write-Progress -Activity "Backing up VCSA" -Completed
$BackupAPI.get("$($BackupJob.ID)") | select id, progress, state
}
Else {

View File

@@ -0,0 +1,699 @@
Function Get-ContentLibrary {
<#
.NOTES
===========================================================================
Created by: William Lam
Organization: VMware
Blog: www.virtuallyghetto.com
Twitter: @lamw
===========================================================================
.DESCRIPTION
This function lists all available vSphere Content Libaries
.PARAMETER LibraryName
The name of a vSphere Content Library
.EXAMPLE
Get-ContentLibrary
.EXAMPLE
Get-ContentLibrary -LibraryName Test
#>
param(
[Parameter(Mandatory=$false)][String]$LibraryName
)
$contentLibaryService = Get-CisService com.vmware.content.library
$libaryIDs = $contentLibaryService.list()
$results = @()
foreach($libraryID in $libaryIDs) {
$library = $contentLibaryService.get($libraryID)
# Use vCenter REST API to retrieve name of Datastore that is backing the Content Library
$datastoreService = Get-CisService com.vmware.vcenter.datastore
$datastore = $datastoreService.get($library.storage_backings.datastore_id)
if($library.publish_info.published) {
$published = $library.publish_info.published
$publishedURL = $library.publish_info.publish_url
$externalReplication = $library.publish_info.persist_json_enabled
} else {
$published = $library.publish_info.published
$publishedURL = "N/A"
$externalReplication = "N/A"
}
if($library.subscription_info) {
$subscribeURL = $library.subscription_info.subscription_url
$published = "N/A"
} else {
$subscribeURL = "N/A"
}
if(!$LibraryName) {
$libraryResult = [pscustomobject] @{
Id = $library.Id;
Name = $library.Name;
Type = $library.Type;
Description = $library.Description;
Datastore = $datastore.name;
Published = $published;
PublishedURL = $publishedURL;
JSONPersistence = $externalReplication;
SubscribedURL = $subscribeURL;
CreationTime = $library.Creation_Time;
}
$results+=$libraryResult
} else {
if($LibraryName -eq $library.name) {
$libraryResult = [pscustomobject] @{
Name = $library.Name;
Id = $library.Id;
Type = $library.Type;
Description = $library.Description;
Datastore = $datastore.name;
Published = $published;
PublishedURL = $publishedURL;
JSONPersistence = $externalReplication;
SubscribedURL = $subscribeURL;
CreationTime = $library.Creation_Time;
}
$results+=$libraryResult
}
}
}
$results
}
Function Get-ContentLibraryItems {
<#
.NOTES
===========================================================================
Created by: William Lam
Organization: VMware
Blog: www.virtuallyghetto.com
Twitter: @lamw
===========================================================================
.DESCRIPTION
This function lists all items within a given vSphere Content Library
.PARAMETER LibraryName
The name of a vSphere Content Library
.PARAMETER LibraryItemName
The name of a vSphere Content Library Item
.EXAMPLE
Get-ContentLibraryItems -LibraryName Test
.EXAMPLE
Get-ContentLibraryItems -LibraryName Test -LibraryItemName TinyPhotonVM
#>
param(
[Parameter(Mandatory=$true)][String]$LibraryName,
[Parameter(Mandatory=$false)][String]$LibraryItemName
)
$contentLibaryService = Get-CisService com.vmware.content.library
$libaryIDs = $contentLibaryService.list()
$results = @()
foreach($libraryID in $libaryIDs) {
$library = $contentLibaryService.get($libraryId)
if($library.name -eq $LibraryName) {
$contentLibaryItemService = Get-CisService com.vmware.content.library.item
$itemIds = $contentLibaryItemService.list($libraryID)
foreach($itemId in $itemIds) {
$item = $contentLibaryItemService.get($itemId)
if(!$LibraryItemName) {
$itemResult = [pscustomobject] @{
Name = $item.name;
Id = $item.id;
Description = $item.description;
Size = $item.size
Type = $item.type;
Version = $item.version;
MetadataVersion = $item.metadata_version;
ContentVersion = $item.content_version;
}
$results+=$itemResult
} else {
if($LibraryItemName -eq $item.name) {
$itemResult = [pscustomobject] @{
Name = $item.name;
Id = $item.id;
Description = $item.description;
Size = $item.size
Type = $item.type;
Version = $item.version;
MetadataVersion = $item.metadata_version;
ContentVersion = $item.content_version;
}
$results+=$itemResult
}
}
}
}
}
$results
}
Function Get-ContentLibraryItemFiles {
<#
.NOTES
===========================================================================
Created by: William Lam
Organization: VMware
Blog: www.virtuallyghetto.com
Twitter: @lamw
===========================================================================
.DESCRIPTION
This function lists all item files within a given vSphere Content Library
.PARAMETER LibraryName
The name of a vSphere Content Library
.PARAMETER LibraryItemName
The name of a vSphere Content Library Item
.EXAMPLE
Get-ContentLibraryItemFiles -LibraryName Test
.EXAMPLE
Get-ContentLibraryItemFiles -LibraryName Test -LibraryItemName TinyPhotonVM
#>
param(
[Parameter(Mandatory=$true)][String]$LibraryName,
[Parameter(Mandatory=$false)][String]$LibraryItemName
)
$contentLibaryService = Get-CisService com.vmware.content.library
$libaryIDs = $contentLibaryService.list()
$results = @()
foreach($libraryID in $libaryIDs) {
$library = $contentLibaryService.get($libraryId)
if($library.name -eq $LibraryName) {
$contentLibaryItemService = Get-CisService com.vmware.content.library.item
$itemIds = $contentLibaryItemService.list($libraryID)
foreach($itemId in $itemIds) {
$itemName = ($contentLibaryItemService.get($itemId)).name
$contenLibraryItemFileSerice = Get-CisService com.vmware.content.library.item.file
$files = $contenLibraryItemFileSerice.list($itemId)
foreach($file in $files) {
if(!$LibraryItemName) {
$fileResult = [pscustomobject] @{
Name = $file.name;
Version = $file.version;
Size = $file.size;
Stored = $file.cached;
}
$results+=$fileResult
} else {
if($itemName -eq $LibraryItemName) {
$fileResult = [pscustomobject] @{
Name = $file.name;
Version = $file.version;
Size = $file.size;
Stored = $file.cached;
}
$results+=$fileResult
}
}
}
}
}
}
$results
}
Function Set-ContentLibrary {
<#
.NOTES
===========================================================================
Created by: William Lam
Organization: VMware
Blog: www.virtuallyghetto.com
Twitter: @lamw
===========================================================================
.DESCRIPTION
This function updates the JSON Persistence property for a given Content Library
.PARAMETER LibraryName
The name of a vSphere Content Library
.EXAMPLE
Set-ContentLibraryItems -LibraryName Test -JSONPersistenceEnabled
.EXAMPLE
Set-ContentLibraryItems -LibraryName Test -JSONPersistenceDisabled
#>
param(
[Parameter(Mandatory=$true)][String]$LibraryName,
[Parameter(Mandatory=$false)][Switch]$JSONPersistenceEnabled,
[Parameter(Mandatory=$false)][Switch]$JSONPersistenceDisabled
)
$contentLibaryService = Get-CisService com.vmware.content.library
$libaryIDs = $contentLibaryService.list()
$found = $false
foreach($libraryID in $libaryIDs) {
$library = $contentLibaryService.get($libraryId)
if($library.name -eq $LibraryName) {
$found = $true
break
}
}
if($found) {
$localLibraryService = Get-CisService -Name "com.vmware.content.local_library"
if($JSONPersistenceEnabled) {
$jsonPersist = $true
} else {
$jsonPersist = $false
}
$updateSpec = $localLibraryService.Help.update.update_spec.Create()
$updateSpec.type = $library.type
$updateSpec.publish_info.authentication_method = $library.publish_info.authentication_method
$updateSpec.publish_info.persist_json_enabled = $jsonPersist
Write-Host "Updating JSON Persistence configuration setting for $LibraryName ..."
$localLibraryService.update($library.id,$updateSpec)
} else {
Write-Host "Unable to find Content Library $Libraryname"
}
}
Function New-ExtReplicatedContentLibrary {
<#
.NOTES
===========================================================================
Created by: William Lam
Organization: VMware
Blog: www.virtuallyghetto.com
Twitter: @lamw
===========================================================================
.DESCRIPTION
This function creates a new Subscriber Content Library from a JSON Persisted
Content Library that has been externally replicated
.PARAMETER LibraryName
The name of the new vSphere Content Library
.PARAMETER DatastoreName
The name of the vSphere Datastore which contains JSON Persisted configuration file
.PARAMETER SubscribeLibraryName
The name fo the root directroy of the externally replicated Content Library residing on vSphere Datastore
.PARAMETER AutoSync
Whether or not to Automatically sync content
.PARAMETER OnDemand
Only sync content when requested
.EXAMPLE
New-ExtReplicatedContentLibrary -LibraryName Bar -DatastoreName iSCSI-02 -SubscribeLibraryName myExtReplicatedLibrary
.EXAMPLE
New-ExtReplicatedContentLibrary -LibraryName Bar -DatastoreName iSCSI-02 -SubscribeLibraryName myExtReplicatedLibrary -AutoSync $false -OnDemand $true
#>
param(
[Parameter(Mandatory=$true)][String]$LibraryName,
[Parameter(Mandatory=$true)][String]$DatastoreName,
[Parameter(Mandatory=$true)][String]$SubscribeLibraryName,
[Parameter(Mandatory=$false)][Boolean]$AutoSync=$false,
[Parameter(Mandatory=$false)][Boolean]$OnDemand=$true
)
$datastore = Get-Datastore -Name $DatastoreName
if($datastore) {
$datastoreId = $datastore.ExtensionData.MoRef.Value
$datastoreUrl = $datastore.ExtensionData.Info.Url
$subscribeUrl = $datastoreUrl + $SubscribeLibraryName + "/lib.json"
$subscribeLibraryService = Get-CisService -Name "com.vmware.content.subscribed_library"
$StorageSpec = [pscustomobject] @{
datastore_id = $datastoreId;
type = "DATASTORE";
}
$UniqueChangeId = [guid]::NewGuid().tostring()
$createSpec = $subscribeLibraryService.Help.create.create_spec.Create()
$createSpec.name = $LibraryName
$addResults = $createSpec.storage_backings.Add($StorageSpec)
$createSpec.subscription_info.automatic_sync_enabled = $false
$createSpec.subscription_info.on_demand = $true
$createSpec.subscription_info.subscription_url = $subscribeUrl
$createSpec.subscription_info.authentication_method = "NONE"
$createSpec.type = "SUBSCRIBED"
Write-Host "Creating new Externally Replicated Content Library called $LibraryName ..."
$library = $subscribeLibraryService.create($UniqueChangeId,$createSpec)
}
}
Function Remove-SubscribedContentLibrary {
<#
.NOTES
===========================================================================
Created by: William Lam
Organization: VMware
Blog: www.virtuallyghetto.com
Twitter: @lamw
===========================================================================
.DESCRIPTION
This function deletes a Subscriber Content Library
.PARAMETER LibraryName
The name of the new vSphere Content Library to delete
.EXAMPLE
Remove-SubscribedContentLibrary -LibraryName Bar
#>
param(
[Parameter(Mandatory=$true)][String]$LibraryName
)
$contentLibaryService = Get-CisService com.vmware.content.library
$libaryIDs = $contentLibaryService.list()
$found = $false
foreach($libraryID in $libaryIDs) {
$library = $contentLibaryService.get($libraryId)
if($library.name -eq $LibraryName) {
$found = $true
break
}
}
if($found) {
$subscribeLibraryService = Get-CisService -Name "com.vmware.content.subscribed_library"
Write-Host "Deleting Subscribed Content Library $LibraryName ..."
$subscribeLibraryService.delete($library.id)
} else {
Write-Host "Unable to find Content Library $LibraryName"
}
}
Function New-LocalContentLibrary {
<#
.NOTES
===========================================================================
Created by: William Lam
Organization: VMware
Blog: www.virtuallyghetto.com
Twitter: @lamw
===========================================================================
.DESCRIPTION
This function creates a new Subscriber Content Library from a JSON Persisted
Content Library that has been externally replicated
.PARAMETER LibraryName
The name of the new vSphere Content Library
.PARAMETER DatastoreName
The name of the vSphere Datastore to store the Content Library
.PARAMETER Publish
Whther or not to publish the Content Library, this is required for JSON Peristence
.PARAMETER JSONPersistence
Whether or not to enable JSON Persistence which enables external replication of Content Library
.EXAMPLE
New-LocalContentLibrary -LibraryName Foo -DatastoreName iSCSI-01 -Publish $true
.EXAMPLE
New-LocalContentLibrary -LibraryName Foo -DatastoreName iSCSI-01 -Publish $true -JSONPersistence $true
#>
param(
[Parameter(Mandatory=$true)][String]$LibraryName,
[Parameter(Mandatory=$true)][String]$DatastoreName,
[Parameter(Mandatory=$false)][Boolean]$Publish=$true,
[Parameter(Mandatory=$false)][Boolean]$JSONPersistence=$false
)
$datastore = Get-Datastore -Name $DatastoreName
if($datastore) {
$datastoreId = $datastore.ExtensionData.MoRef.Value
$localLibraryService = Get-CisService -Name "com.vmware.content.local_library"
$StorageSpec = [pscustomobject] @{
datastore_id = $datastoreId;
type = "DATASTORE";
}
$UniqueChangeId = [guid]::NewGuid().tostring()
$createSpec = $localLibraryService.Help.create.create_spec.Create()
$createSpec.name = $LibraryName
$addResults = $createSpec.storage_backings.Add($StorageSpec)
$createSpec.publish_info.authentication_method = "NONE"
$createSpec.publish_info.persist_json_enabled = $JSONPersistence
$createSpec.publish_info.published = $Publish
$createSpec.type = "LOCAL"
Write-Host "Creating new Local Content Library called $LibraryName ..."
$library = $localLibraryService.create($UniqueChangeId,$createSpec)
}
}
Function Remove-LocalContentLibrary {
<#
.NOTES
===========================================================================
Created by: William Lam
Organization: VMware
Blog: www.virtuallyghetto.com
Twitter: @lamw
===========================================================================
.DESCRIPTION
This function deletes a Local Content Library
.PARAMETER LibraryName
The name of the new vSphere Content Library to delete
.EXAMPLE
Remove-LocalContentLibrary -LibraryName Bar
#>
param(
[Parameter(Mandatory=$true)][String]$LibraryName
)
$contentLibaryService = Get-CisService com.vmware.content.library
$libaryIDs = $contentLibaryService.list()
$found = $false
foreach($libraryID in $libaryIDs) {
$library = $contentLibaryService.get($libraryId)
if($library.name -eq $LibraryName) {
$found = $true
break
}
}
if($found) {
$localLibraryService = Get-CisService -Name "com.vmware.content.local_library"
Write-Host "Deleting Local Content Library $LibraryName ..."
$localLibraryService.delete($library.id)
} else {
Write-Host "Unable to find Content Library $LibraryName"
}
}
Function Copy-ContentLibrary {
<#
.NOTES
===========================================================================
Created by: William Lam
Organization: VMware
Blog: www.virtuallyghetto.com
Twitter: @lamw
===========================================================================
.DESCRIPTION
This function copies all library items from one Content Library to another
.PARAMETER SourceLibaryName
The name of the source Content Library to copy from
.PARAMETER DestinationLibaryName
The name of the desintation Content Library to copy to
.PARAMETER DeleteSourceFile
Whther or not to delete library item from the source Content Library after copy
.EXAMPLE
Copy-ContentLibrary -SourceLibaryName Foo -DestinationLibaryName Bar
.EXAMPLE
Copy-ContentLibrary -SourceLibaryName Foo -DestinationLibaryName Bar -DeleteSourceFile $true
#>
param(
[Parameter(Mandatory=$true)][String]$SourceLibaryName,
[Parameter(Mandatory=$true)][String]$DestinationLibaryName,
[Parameter(Mandatory=$false)][Boolean]$DeleteSourceFile=$false
)
$sourceLibraryId = (Get-ContentLibrary -LibraryName $SourceLibaryName).Id
if($sourceLibraryId -eq $null) {
Write-Host -ForegroundColor red "Unable to find Source Content Library named $SourceLibaryName"
exit
}
$destinationLibraryId = (Get-ContentLibrary -LibraryName $DestinationLibaryName).Id
if($destinationLibraryId -eq $null) {
Write-Host -ForegroundColor Red "Unable to find Destination Content Library named $DestinationLibaryName"
break
}
$sourceItemFiles = Get-ContentLibraryItems -LibraryName $SourceLibaryName
if($sourceItemFiles -eq $null) {
Write-Host -ForegroundColor red "Unable to retrieve Content Library Items from $SourceLibaryName"
break
}
$contentLibaryItemService = Get-CisService com.vmware.content.library.item
foreach ($sourceItemFile in $sourceItemFiles) {
# Check to see if file already exists in destination Content Library
$result = Get-ContentLibraryItems -LibraryName $DestinationLibaryName -LibraryItemName $sourceItemFile.Name
if($result -eq $null) {
# Create CopySpec
$copySpec = $contentLibaryItemService.Help.copy.destination_create_spec.Create()
$copySpec.library_id = $destinationLibraryId
$copySpec.name = $sourceItemFile.Name
$copySpec.description = $sourceItemFile.Description
# Create random Unique Copy Id
$UniqueChangeId = [guid]::NewGuid().tostring()
# Perform Copy
try {
Write-Host -ForegroundColor Cyan "Copying" $sourceItemFile.Name "..."
$copyResult = $contentLibaryItemService.copy($UniqueChangeId, $sourceItemFile.Id, $copySpec)
} catch {
Write-Host -ForegroundColor Red "Failed to copy" $sourceItemFile.Name
$Error[0]
break
}
# Delete source file if set to true
if($DeleteSourceFile) {
try {
Write-Host -ForegroundColor Magenta "Deleteing" $sourceItemFile.Name "..."
$deleteResult = $contentLibaryItemService.delete($sourceItemFile.Id)
} catch {
Write-Host -ForegroundColor Red "Failed to delete" $sourceItemFile.Name
$Error[0]
break
}
}
} else {
Write-Host -ForegroundColor Yellow "Skipping" $sourceItemFile.Name "already exists"
# Delete source file if set to true
if($DeleteSourceFile) {
try {
Write-Host -ForegroundColor Magenta "Deleteing" $sourceItemFile.Name "..."
$deleteResult = $contentLibaryItemService.delete($sourceItemFile.Id)
} catch {
Write-Host -ForegroundColor Red "Failed to delete" $sourceItemFile.Name
break
}
}
}
}
}
Function New-VMTX {
<#
.NOTES
===========================================================================
Created by: William Lam
Organization: VMware
Blog: www.virtuallyghetto.com
Twitter: @lamw
===========================================================================
.DESCRIPTION
This function clones a VM to VM Template in Content Library (currently only supported on VMC)
.PARAMETER SourceVMName
The name of the source VM to clone
.PARAMETER VMTXName
The name of the VM Template in Content Library
.PARAMETER Description
Description of the VM template
.PARAMETER LibaryName
The name of the Content Library to clone to
.PARAMETER FolderName
The name of vSphere Folder (Defaults to Workloads for VMC)
.PARAMETER ResourcePoolName
The name of the vSphere Resource Pool (Defaults to Compute-ResourcePools for VMC)
.EXAMPLE
New-VMTX -SourceVMName "Windows10-BaseInstall" -VMTXName "Windows10-VMTX-Template" -LibraryName "VMC-CL-01"
#>
param(
[Parameter(Mandatory=$true)][String]$SourceVMName,
[Parameter(Mandatory=$true)][String]$VMTXName,
[Parameter(Mandatory=$false)][String]$Description,
[Parameter(Mandatory=$true)][String]$LibraryName,
[Parameter(Mandatory=$false)][String]$FolderName="Workloads",
[Parameter(Mandatory=$false)][String]$ResourcePoolName="Compute-ResourcePool"
)
$vmtxService = Get-CisService -Name "com.vmware.vcenter.vm_template.library_items"
$sourceVMId = ((Get-VM -Name $SourceVMName).ExtensionData.MoRef).Value
$libraryId = ((Get-ContentLibrary -LibraryName $LibraryName).Id).Value
$folderId = ((Get-Folder -Name $FolderName).ExtensionData.MoRef).Value
$rpId = ((Get-ResourcePool -Name $ResourcePoolName).ExtensionData.MoRef).Value
$vmtxCreateSpec = $vmtxService.Help.create.spec.Create()
$vmtxCreateSpec.source_vm = $sourceVMId
$vmtxCreateSpec.name = $VMTXName
$vmtxCreateSpec.description = $Description
$vmtxCreateSpec.library = $libraryId
$vmtxCreateSpec.placement.folder = $folderId
$vmtxCreateSpec.placement.resource_pool = $rpId
Write-Host "`nCreating new VMTX Template from $SourceVMName in Content Library $LibraryName ..."
$result = $vmtxService.create($vmtxCreateSpec)
}
Function New-VMFromVMTX {
<#
.NOTES
===========================================================================
Created by: William Lam
Organization: VMware
Blog: www.virtuallyghetto.com
Twitter: @lamw
===========================================================================
.DESCRIPTION
This function deploys a new VM from Template in Content Library (currently only supported in VMC)
.PARAMETER VMTXName
The name of the VM Template in Content Library to deploy from
.PARAMETER NewVMName
The name of the new VM to deploy
.PARAMETER FolderName
The name of vSphere Folder (Defaults to Workloads for VMC)
.PARAMETER ResourcePoolName
The name of the vSphere Resource Pool (Defaults to Compute-ResourcePools for VMC)
.PARAMETER NumCpu
The number of vCPU to configure for the new VM
.PARAMETER MemoryMb
The amount of memory (MB) to configure for the new VM
.PARAMETER PowerOn
To power on the VM after deploy
.EXAMPLE
New-VMFromVMTX -NewVMName "FooFoo" -VMTXName "FooBar" -PowerOn $true -NumCpu 4 -MemoryMB 2048
#>
param(
[Parameter(Mandatory=$true)][String]$VMTXName,
[Parameter(Mandatory=$true)][String]$NewVMName,
[Parameter(Mandatory=$false)][String]$FolderName="Workloads",
[Parameter(Mandatory=$false)][String]$ResourcePoolName="Compute-ResourcePool",
[Parameter(Mandatory=$false)][String]$DatastoreName="WorkloadDatastore",
[Parameter(Mandatory=$false)][Int]$NumCpu,
[Parameter(Mandatory=$false)][Int]$MemoryMB,
[Parameter(Mandatory=$false)][Boolean]$PowerOn=$false
)
$vmtxService = Get-CisService -Name "com.vmware.vcenter.vm_template.library_items"
$vmtxId = (Get-ContentLibraryItem -Name $VMTXName).Id
$folderId = ((Get-Folder -Name $FolderName).ExtensionData.MoRef).Value
$rpId = ((Get-ResourcePool -Name $ResourcePoolName).ExtensionData.MoRef).Value
$datastoreId = ((Get-Datastore -Name $DatastoreName).ExtensionData.MoRef).Value
$vmtxDeploySpec = $vmtxService.Help.deploy.spec.Create()
$vmtxDeploySpec.name = $NewVMName
$vmtxDeploySpec.powered_on = $PowerOn
$vmtxDeploySpec.placement.folder = $folderId
$vmtxDeploySpec.placement.resource_pool = $rpId
$vmtxDeploySpec.vm_home_storage.datastore = $datastoreId
$vmtxDeploySpec.disk_storage.datastore = $datastoreId
if($NumCpu) {
$vmtxDeploySpec.hardware_customization.cpu_update.num_cpus = $NumCpu
}
if($MemoryMB) {
$vmtxDeploySpec.hardware_customization.memory_update.memory = $MemoryMB
}
Write-Host "`nDeploying new VM $NewVMName from VMTX Template $VMTXName ..."
$results = $vmtxService.deploy($vmtxId,$vmtxDeploySpec)
}

View File

@@ -0,0 +1,298 @@
Function Get-XVCMStatus {
<#
.NOTES
===========================================================================
Created by: William Lam
Organization: VMware
Blog: www.virtuallyghetto.com
Twitter: @lamw
===========================================================================
.DESCRIPTION
This function returns whether Cross vCenter Workload Migration Utility is running or not
.EXAMPLE
Get-XVCMStatus
#>
$Uri = "http://localhost:8080/api/status" #Updated for 2.0, Old: "http://localhost:8080/api/ping"
$results = Invoke-WebRequest -Uri $Uri -Method GET -TimeoutSec 5
if($results.StatusCode -eq 200) {
Write-Host -ForegroundColor Green $results.Content
} else { Write-Host -ForegroundColor Red "Cross vCenter Workload Migration Utility is probably not running" }
}
Function Get-XVCMSite {
<#
.NOTES
===========================================================================
Created by: William Lam
Organization: VMware
Blog: www.virtuallyghetto.com
Twitter: @lamw
===========================================================================
.DESCRIPTION
This function returns all registered vCenter Servers
.EXAMPLE
Get-XVCMSite
#>
$Uri = "http://localhost:8080/api/sites"
$results = Invoke-WebRequest -Uri $Uri -Method GET
if($results.StatusCode -eq 200) {
($results.Content | ConvertFrom-Json)|select sitename,hostname,username
} else { Write-Host -ForegroundColor Red "Failed to retrieve VC Site Registration details" }
}
Function New-XVCMSite {
<#
.NOTES
===========================================================================
Created by: William Lam
Organization: VMware
Blog: www.virtuallyghetto.com
Twitter: @lamw
===========================================================================
.DESCRIPTION
This function registers a new vCenter Server endpoint
.PARAMETER SiteName
The display name for the particular vCenter Server to be registered
.PARAMETER VCHostname
The Hostname/IP Address of vCenter Server
.PARAMETER VCUsername
The VC Username of vCenter Server
.PARAMETER VCPassword
The VC Password of vCenter Server
.PARAMETER Insecure
Flag to disable SSL Verification checking, useful for lab environments
.EXAMPLE
New-XVCMSite -SiteName "SiteA" -VCHostname "vcenter65-1.primp-industries.com" -VCUsername "administrator@vsphere.local" -VCPassword "VMware1!" -Insecure
#>
param(
[Parameter(Mandatory=$true)][String]$SiteName,
[Parameter(Mandatory=$true)][String]$VCHostname,
[Parameter(Mandatory=$true)][String]$VCUsername,
[Parameter(Mandatory=$true)][String]$VCPassword,
[Parameter(Mandatory=$false)][Switch]$Insecure
)
$Uri = "http://localhost:8080/api/sites"
$insecureFlag = $false
if($Insecure) {
$insecureFlag = $true
}
$body = @{
"sitename"=$SiteName;
"hostname"=$VCHostname;
"username"=$VCUsername;
"password"=$VCPassword;
"insecure"=$insecureFlag;
}
$body = $body | ConvertTo-Json
Write-Host -ForegroundColor Cyan "Registering vCenter Server $VCHostname as $SiteName ..."
$results = Invoke-WebRequest -Uri $Uri -Method POST -Body $body -ContentType "application/json"
if($results.StatusCode -eq 200) {
Write-Host -ForegroundColor Green "Successfully registered $SiteName"
} else { Write-Host -ForegroundColor Red "Failed to register $SiteName" }
}
Function Remove-XVCMSite {
<#
.NOTES
===========================================================================
Created by: William Lam
Organization: VMware
Blog: www.virtuallyghetto.com
Twitter: @lamw
===========================================================================
.DESCRIPTION
This function removes vCenter Server endpoint
.PARAMETER SiteName
The name of the registered vCenter Server to remove
.EXAMPLE
Remove-XVCMSite -SiteName "SiteA"
#>
param(
[Parameter(Mandatory=$true)][String]$SiteName
)
$Uri = "http://localhost:8080/api/sites/$SiteName"
Write-Host -ForegroundColor Cyan "Deleting vCenter Server Site Registerion $SiteName ..."
$results = Invoke-WebRequest -Uri $Uri -Method DELETE
if($results.StatusCode -eq 200) {
Write-Host -ForegroundColor Green "Successfully deleted $SiteName"
} else { Write-Host -ForegroundColor Red "Failed to deleted $SiteName" }
}
Function New-XVCMRequest {
<#
.NOTES
===========================================================================
Created by: William Lam
Organization: VMware
Blog: www.virtuallyghetto.com
Twitter: @lamw
===========================================================================
.DESCRIPTION
This function initiates a migration request
.PARAMETER opType
The type of task, Relocate or Clone
.PARAMETER SrcSite
The name of the source vCenter Server
.PARAMETER DstSite
The name of the destination vCenter Server
.PARAMETER SrcDatacenter
The name of the source vSphere Datacenter
.PARAMETER DstDatacenter
The name of the destination vSphere Datacenter
.PARAMETER SrcCluster
<Not needed for v2.0,removed from code>
.PARAMETER DstCluster
The name of the destination vSphere Cluster, set to null if DstHost is defined
.PARAMETER DstDatastore
The name of the destination Datastore
.PARAMETER DstHost
The name of the destination host. Set to null if DstCluster is defined
.PARAMETER srcVMs
List of VMs to migrate
.PARAMETER NetworkMapping
Hash table of the VM network mappings between your source and destination vCenter Server
.EXAMPLE
New-XVCMRequest -opType Relocate -SrcSite SiteA -DstSite SiteB `
-SrcDatacenter Datacenter-SiteA -DstDatacenter Datacenter-SiteB `
-DstCluster $null -DstHost VMhost1.test.lab `
-DstDatastore vsanDatastore `
-srcVMs @("PhotonOS-01","PhotonOS-02","PhotonOS-03","PhotonOS-04") `
-NetworkMapping @{"DVPG-VM Network 1"="DVPG-Internal Network";"DVPG-VM Network 2"="DVPG-External Network"}
#>
param(
[Parameter(Mandatory=$true)][String]$opType, #Added by CPM for 2.0
[Parameter(Mandatory=$true)][String]$SrcSite,
[Parameter(Mandatory=$true)][String]$DstSite,
[Parameter(Mandatory=$true)][String]$SrcDatacenter,
[Parameter(Mandatory=$true)][String]$DstDatacenter,
#[Parameter(Mandatory=$true)][String]$SrcCluster, #Removed by CPM for 2.0
[Parameter(Mandatory=$true)][AllowNull()] $DstCluster, #Added [AllowNull()], removed [String] by CPM for 2.0
[Parameter(Mandatory=$true)][String]$DstDatastore,
[Parameter(Mandatory=$true)][AllowNull()] $DstHost, #Added by CPM for 2.0
[Parameter(Mandatory=$true)][String[]]$srcVMs,
[Parameter(Mandatory=$true)][Hashtable]$NetworkMapping
)
$Uri = "http://localhost:8080/api/tasks"
$body = @{
"sourceSite"=$SrcSite;
"targetSite"=$DstSite;
"sourceDatacenter"=$SrcDatacenter;
"targetDatacenter"=$dstDatacenter;
#"sourceCluster"=$SrcCluster; #Removed by CPM for 2.0
"targetCluster"=$DstCluster;
"targetDatastore"=$DstDatastore;
"targetHost"=$DstHost; #Added by CPM for 2.0
"networkMap"=$NetworkMapping;
"vmList"=$srcVMs;
"operationType"=$opType; #Added by CPM for 2.0
}
$body = $body | ConvertTo-Json
Write-Host -ForegroundColor Cyan "Initiating migration request ..."
$results = Invoke-WebRequest -Uri $Uri -Method POST -Body $body -ContentType "application/json"
if($results.StatusCode -eq 200) {
$taskId = ($results.Content | ConvertFrom-Json).requestId
Write-Host -ForegroundColor Green "Successfully issued migration with TaskID: $taskId"
} else { Write-Host -ForegroundColor Red "Failed to initiate migration request" }
}
Function Get-XVCMTask {
<#
.NOTES
===========================================================================
Created by: William Lam
Organization: VMware
Blog: www.virtuallyghetto.com
Twitter: @lamw
===========================================================================
.DESCRIPTION
This function retrieves either all migration tasks and/or a specific migration task
.PARAMETER Id
The task ID returned from initiating a migration
.EXAMPLE
Get-XVCMTask -Id <Task ID>
#>
param(
[Parameter(Mandatory=$false)][String]$Id
)
$Uri = "http://localhost:8080/api/tasks"
if($Id) {
$body = @{"requestId"=$Id}
$results = Invoke-WebRequest -Uri $Uri -Method GET -Body $body -ContentType "application/json"
} else {
$results = Invoke-WebRequest -Uri $Uri -Method GET
}
if($results.StatusCode -eq 200) {
$results.Content | ConvertFrom-Json
} else { Write-Host -ForegroundColor Red "Failed to retrieve tasks" }
}
Function Get-VMNetwork {
<#
.NOTES
===========================================================================
Created by: William Lam
Organization: VMware
Blog: www.virtuallyghetto.com
Twitter: @lamw
===========================================================================
.DESCRIPTION
This function returns the list of all VM Networks attached to
given VMs to help with initiating migration
.PARAMETER srcVMs
List of VMs to query their current VM Networks
.EXAMPLE
Get-VMNetwork -srcVMs @("PhotonOS-01","PhotonOS-02","PhotonOS-03","PhotonOS-04")
#>
param(
[Parameter(Mandatory=$false)][String[]]$srcVMs
)
if (-not $global:DefaultVIServers) { Write-Host -ForegroundColor red "No vCenter Server Connection found, please connect to your source vCenter Server using Connect-VIServer"; break }
$results = @()
if($srcVMs) {
foreach ($srcVM in $srcVMs) {
$vm = Get-VM -Name $srcVM
$networkDetails = $vm | Get-NetworkAdapter
$tmp = [pscustomobject] @{
Name = $srcVM;
Adapter = $networkDetails.name;
Network = $networkDetails.NetworkName;
}
$results+=$tmp
}
} else {
foreach ($vm in Get-VM) {
$networkDetails = $vm | Get-NetworkAdapter
$tmp = [pscustomobject] @{
Name = $vm.Name;
Adapter = $networkDetails.name;
Network = $networkDetails.NetworkName;
}
$results+=$tmp
}
}
$results
}

View File

@@ -0,0 +1,245 @@
<#
.SYNOPSIS Datastore Functions
.DESCRIPTION A collection of functions to manipulate datastore Mount + Attach status
.EXAMPLE Get-Datastore | Get-DatastoreMountInfo | Sort Datastore, VMHost | FT -AutoSize
.EXAMPLE Get-Datastore IX2ISCSI01 | Unmount-Datastore
.EXAMPLE Get-Datastore IX2ISCSI01 | Get-DatastoreMountInfo | Sort Datastore, VMHost | FT -AutoSize
.EXAMPLE Get-Datastore IX2iSCSI01 | Mount-Datastore
.EXAMPLE Get-Datastore IX2iSCSI01 | Get-DatastoreMountInfo | Sort Datastore, VMHost | FT -AutoSize
.EXAMPLE Get-Datastore IX2iSCSI01 | Detach-Datastore
.EXAMPLE Get-Datastore IX2iSCSI01 | Get-DatastoreMountInfo | Sort Datastore, VMHost | FT -AutoSize
.EXAMPLE Get-Datastore IX2iSCSI01 | Attach-datastore
.EXAMPLE Get-Datastore IX2iSCSI01 | Get-DatastoreMountInfo | Sort Datastore, VMHost | FT -AutoSize
.NOTES Written by Alan Renouf, originally published at https://blogs.vmware.com/vsphere/2012/01/automating-datastore-storage-device-detachment-in-vsphere-5.html
.NOTES May 2017: Modified by Jason Coleman (virtuallyjason.blogspot.com), to improve performance when dealing with a large number of hosts and datastores
#>
Function Get-HostViews {
[CmdletBinding()]
Param (
$Datastore
)
Begin{
$allDatastores = @()
}
Process {
$allDatastores += $Datastore
}
End {
#Build the array of Datastore Objects
if (-not $Datastore) {
$allDatastores = Get-Datastore
}
$allDatastores = $allDatastores | ? {$_.pstypenames -contains "VMware.VimAutomation.ViCore.Impl.V1.DatastoreManagement.DatastoreImpl"}
if (-not $allDatastores){
Throw "No Datastores found.`nIs ""$Datastore"" a Datastore Object?"
}
$allHosts = @()
$DShostsKeys = $allDatastores.extensiondata.host.key.value | sort | get-unique -asstring
$DShosts = foreach ($thisKey in $DShostsKeys) {($allDatastores.extensiondata.host | ? {$_.key.value -eq $thisKey})[0]}
$i = 1
foreach ($DSHost in $DSHosts){
write-progress -activity "Collecting ESXi Host Views" -status "Querying $($dshost.key)..." -percentComplete ($i++/$DSHosts.count*100)
$hostObj = "" | select keyValue,hostView,storageSys
$hostObj.hostView = get-view $DSHost.key
$hostObj.keyValue = $DSHost.key.value
$hostObj.storageSys = Get-View $hostObj.hostView.ConfigManager.StorageSystem
$allHosts += $hostObj
}
write-progress -activity "Collecting ESXi Host Views" -completed
$allHosts
}
}
Function Get-DatastoreMountInfo {
[CmdletBinding()]
Param (
[Parameter(ValueFromPipeline=$true)]
$Datastore
)
#Roll back up an unrolled array from a pipeline
Begin{
$allDatastores = @()
}
Process {
$allDatastores += $Datastore
}
End {
$AllInfo = @()
#Build the array of Datastore Objects
if (-not $Datastore) {
$allDatastores = Get-Datastore
}
$allDatastores = $allDatastores | ? {$_.pstypenames -contains "VMware.VimAutomation.ViCore.Impl.V1.DatastoreManagement.DatastoreImpl"}
if (-not $allDatastores){
Throw "No Datastores found.`nIs ""$Datastore"" a Datastore Object?"
}
$allDatastoreNAAs = foreach ($ds in $allDatastores) {$ds.ExtensionData.Info.vmfs.extent[0].diskname}
#Build the array of custom Host Objects
$allHosts = Get-HostViews -datastore $allDatastores
$output = @()
$i = 1
foreach ($dsHost in $allHosts){
write-progress -activity "Checking Datastore access" -status "Checking $($dshost.hostview.name)..." -percentComplete ($i++ / $allHosts.count * 100)
#Get all devices on the host that match the list of $allDatastoreNAAs
$devices = $dsHost.storagesys.StorageDeviceInfo.ScsiLun
foreach ($device in $devices){
if ($allDatastoreNAAs -contains $device.canonicalName){
#Record information about this device/host combo
$thisDatastore = $alldatastores | ? {$_.ExtensionData.Info.vmfs.extent[0].diskname -eq $device.canonicalName}
$hostviewDSAttachState = ""
if ($device.operationalState[0] -eq "ok") {
$hostviewDSAttachState = "Attached"
} elseif ($device.operationalState[0] -eq "off") {
$hostviewDSAttachState = "Detached"
} else {
$hostviewDSAttachState = $device.operationalstate[0]
}
$Info = "" | Select Datastore, VMHost, Lun, Mounted, State
$Info.VMHost = $dsHost.hostview.name
$Info.Datastore = $thisDatastore.name
$Info.Lun = $device.canonicalName
$Info.mounted = ($thisDatastore.extensiondata.host | ? {$_.key.value -eq $dshost.keyvalue}).mountinfo.mounted
$Info.state = $hostviewDSAttachState
$output += $info
}
}
}
write-progress -activity "Checking Datastore access" -completed
$output
}
}
Function Detach-Datastore {
[CmdletBinding()]
Param (
[Parameter(ValueFromPipeline=$true)]
$Datastore
)
Begin{
$allDatastores = @()
}
Process {
$allDatastores += $Datastore
}
End {
$allDatastores = $allDatastores | ? {$_.pstypenames -contains "VMware.VimAutomation.ViCore.Impl.V1.DatastoreManagement.DatastoreImpl"}
if (-not $allDatastores){
Throw "No Datastores found.`nIs ""$Datastore"" a Datastore Object?"
}
$allDatastoreNAAs = foreach ($ds in $allDatastores) {$ds.ExtensionData.Info.vmfs.extent[0].diskname}
$allHosts = Get-HostViews -datastore $allDatastores
$j = 1
foreach ($dsHost in $allHosts){
#Get all devices on the host that match the list of $allDatastoreNAAs
write-progress -id 1 -activity "Detaching Datastores" -status "Removing device(s) from $($dsHost.hostview.name)" -percentComplete ($j++ / $allHosts.count * 100)
$devices = $dsHost.storagesys.StorageDeviceInfo.ScsiLun | ? {$allDatastoreNAAs -contains $_.canonicalName}
$i = 1
foreach ($device in $devices){
write-progress -parentid 1 -activity "Detaching Datastores" -status "Removing device: $(($allDatastores | ? {$_.ExtensionData.Info.vmfs.extent[0].diskname -eq $device.canonicalName}).name)" -percentComplete ($i++ / $allDatastoreNAAs.count * 100)
$LunUUID = $Device.Uuid
$dsHost.storageSys.DetachScsiLun($LunUUID);
}
}
write-progress -activity "Detaching Datastores" -completed
}
}
Function Attach-Datastore {
[CmdletBinding()]
Param (
[Parameter(ValueFromPipeline=$true)]
$Datastore
)
Begin{
$allDatastores = @()
}
Process {
$allDatastores += $Datastore
}
End {
$allDatastores = $allDatastores | ? {$_.pstypenames -contains "VMware.VimAutomation.ViCore.Impl.V1.DatastoreManagement.DatastoreImpl"}
if (-not $allDatastores){
Throw "No Datastores found.`nIs ""$Datastore"" a Datastore Object?"
}
$allDatastoreNAAs = foreach ($ds in $allDatastores) {$ds.ExtensionData.Info.vmfs.extent[0].diskname}
$allHosts = Get-HostViews -datastore $allDatastores
$j = 1
foreach ($dsHost in $allHosts){
#Get all devices on the host that match the list of $allDatastoreNAAs
write-progress -id 1 -activity "Attaching Datastores" -status "Attaching devices to $($dsHost.hostview.name)" -percentComplete ($j++ / $allHosts.count * 100)
$devices = $dsHost.storagesys.StorageDeviceInfo.ScsiLun
$i = 1
foreach ($device in $devices){
write-progress -parentid 1 -activity "Attaching Datastores" -status "Attaching device: $($Device.Uuid)" -percentComplete ($i++ / $devices.count * 100)
if ($allDatastoreNAAs -contains $device.canonicalName){
$LunUUID = $Device.Uuid
$dsHost.storageSys.AttachScsiLun($LunUUID);
}
}
}
write-progress -activity "Attaching Datastores" -completed
}
}
Function Unmount-Datastore {
[CmdletBinding()]
Param (
[Parameter(ValueFromPipeline=$true)]
$Datastore
)
Begin{
$allDatastores = @()
}
Process {
$allDatastores += $Datastore
}
End {
$allDatastores = $allDatastores | ? {$_.pstypenames -contains "VMware.VimAutomation.ViCore.Impl.V1.DatastoreManagement.DatastoreImpl"}
if (-not $allDatastores){
Throw "No Datastores found.`nIs ""$Datastore"" a Datastore Object?"
}
$allHosts = Get-HostViews -datastore $allDatastores
$j = 1
foreach ($dsHost in $allHosts){
write-progress -id 1 -activity "Unmounting Datastores" -status "Unmounting devices from $($dsHost.hostview.name)" -percentComplete ($j++ / $allHosts.count * 100)
$i = 1
foreach ($ds in $allDatastores){
write-progress -parentid 1 -activity "Unmounting Datastores" -status "Unmounting device: $($ds.name)" -percentComplete ($i++ / $allDatastores.count * 100)
$dsHost.storageSys.UnmountVmfsVolume($DS.ExtensionData.Info.vmfs.uuid);
}
}
write-progress -activity "Unmounting Datastores" -completed
}
}
Function Mount-Datastore {
[CmdletBinding()]
Param (
[Parameter(ValueFromPipeline=$true)]
$Datastore
)
Begin{
$allDatastores = @()
}
Process {
$allDatastores += $Datastore
}
End {
$allDatastores = $allDatastores | ? {$_.pstypenames -contains "VMware.VimAutomation.ViCore.Impl.V1.DatastoreManagement.DatastoreImpl"}
if (-not $allDatastores){
Throw "No Datastores found.`nIs ""$Datastore"" a Datastore Object?"
}
$allHosts = Get-HostViews -datastore $allDatastores
$j = 0
foreach ($dsHost in $allHosts){
write-progress -activity "Mounting Datastores" -status "Mounting devices to $($dsHost.hostview.name)" -percentComplete ($j++ / $allHosts.count * 100)
$i = 1
foreach ($ds in $allDatastores){
write-progress -activity "Mounting Datastores" -status "Mounting device: $($DS.ExtensionData.Info.vmfs.uuid)" -percentComplete ($i++ / $allDatastores.count * 100)
$dsHost.storageSys.MountVmfsVolume($DS.ExtensionData.Info.vmfs.uuid);
}
}
write-progress -activity "Mounting Datastores" -completed
}
}

View File

@@ -0,0 +1,93 @@
function Get-NICDetails {
<#
.NOTES
===========================================================================
Created by: Markus Kraus
Twitter: @VMarkus_K
Private Blog: mycloudrevolution.com
===========================================================================
Changelog:
2017.02 ver 1.0 Base Release
===========================================================================
External Code Sources:
-
===========================================================================
Tested Against Environment:
vSphere Version: ESXi 6.0 U2, ESXi 6.5
PowerCLI Version: PowerCLI 6.3 R1, PowerCLI 6.5 R1
PowerShell Version: 4.0, 5.0
OS Version: Windows 8.1, Server 2008 R2, Server 2012 R2
Keyword: ESXi, NIC, vmnic, Driver, Firmware
===========================================================================
.DESCRIPTION
Reports Firmware and Driver Details for your ESXi vmnics.
.Example
Get-NICDetails -Clustername *
.PARAMETER Clustername
Name or Wildcard of your vSphere Cluster Name to process.
#Requires PS -Version 4.0
#Requires -Modules VMware.VimAutomation.Core, @{ModuleName="VMware.VimAutomation.Core";ModuleVersion="6.3.0.0"}
#>
[CmdletBinding()]
param(
[Parameter(Mandatory=$True, ValueFromPipeline=$False, Position=0)]
[ValidateNotNullorEmpty()]
[String] $Clustername
)
Begin {
$Validate = $True
if (($myCluster = Get-Cluster -Name $Clustername).count -lt 1) {
$Validate = $False
thow "No Cluster '$myCluster' found!"
}
}
Process {
$MyView = @()
if ($Validate -eq $True) {
foreach ($myVMhost in ($myCluster | Get-VMHost)) {
$esxcli2 = Get-ESXCLI -VMHost $myVMhost -V2
$niclist = $esxcli2.network.nic.list.invoke()
$nicdetails = @()
foreach ($nic in $niclist) {
$args = $esxcli2.network.nic.get.createargs()
$args.nicname = $nic.name
$nicdetail = $esxcli2.network.nic.get.Invoke($args)
$nicdetails += $nicdetail
}
ForEach ($nicdetail in $nicdetails){
$NICReport = [PSCustomObject] @{
Host = $myVMhost.Name
vmnic = $nicdetail.Name
LinkStatus = $nicdetail.LinkStatus
BusInfo = $nicdetail.driverinfo.BusInfo
Driver = $nicdetail.driverinfo.Driver
FirmwareVersion = $nicdetail.driverinfo.FirmwareVersion
DriverVersion = $nicdetail.driverinfo.Version
}
$MyView += $NICReport
}
}
$MyView
}
}
}

View File

@@ -0,0 +1,98 @@
Function New-InstantClone {
<#
.NOTES
===========================================================================
Created by: William Lam
Date: Apr 29, 2018
Organization: VMware
Blog: www.virtuallyghetto.com
Twitter: @lamw
===========================================================================
.SYNOPSIS
This function demonstrates the use of the new "Parentless" Instant Clone
API that was introduced in vSphere 6.7
.DESCRIPTION
Function to create new "Parentless" Instant Clones in vSphere 6.7
.EXAMPLE
$SourceVM = "Foo"
$newVMName = Foo-IC-1
$guestCustomizationValues = @{
"guestinfo.ic.hostname" = $newVMName
"guestinfo.ic.ipaddress" = "192.168.30.10"
"guestinfo.ic.netmask" = "255.255.255.0"
"guestinfo.ic.gateway" = "192.168.30.1"
"guestinfo.ic.dns" = "192.168.30.1"
}
New-InstantClone -SourceVM $SourceVM -DestinationVM $newVMName -CustomizationFields $guestCustomizationValues
.NOTES
Make sure that you have both a vSphere 6.7 env (VC/ESXi) as well as
as the latest PowerCLI 10.1 installed which is reuqired to use vSphere 6.7 APIs
#>
param(
[Parameter(Mandatory=$true)][String]$SourceVM,
[Parameter(Mandatory=$true)][String]$DestinationVM,
[Parameter(Mandatory=$true)][Hashtable]$CustomizationFields
)
$vm = Get-VM -Name $SourceVM
$config = @()
$CustomizationFields.GetEnumerator() | Foreach-Object {
$optionValue = New-Object VMware.Vim.OptionValue
$optionValue.Key = $_.Key
$optionValue.Value = $_.Value
$config += $optionValue
}
# SourceVM must either be running or running but in Frozen State
if($vm.PowerState -ne "poweredOn") {
Write-Host -ForegroundColor Red "Instant Cloning is only supported on a PoweredOn or Frozen VM"
break
}
# SourceVM == Powered On
if((Get-VM $SourceVM).ExtensionData.Runtime.InstantCloneFrozen -eq $false) {
# Retrieve all Network Adapters for SourceVM
$vmNetworkAdapters = @()
$devices = $vm.ExtensionData.Config.Hardware.Device
foreach ($device in $devices) {
if($device -is [VMware.Vim.VirtualEthernetCard]) {
$vmNetworkAdapters += $device
}
}
$spec = New-Object VMware.Vim.VirtualMachineInstantCloneSpec
$locationSpec = New-Object VMware.Vim.VirtualMachineRelocateSpec
# Disconect all NICs for new Instant Clone to ensure no dupe addresses on network
# post-Instant Clone workflow needs to renable after uypdating GuestOS
foreach ($vmNetworkAdapter in $vmNetworkAdapters) {
$networkName = $vmNetworkAdapter.backing.deviceName
$deviceConfigSpec = New-Object VMware.Vim.VirtualDeviceConfigSpec
$deviceConfigSpec.Operation = "edit"
$deviceConfigSpec.Device = $vmNetworkAdapter
$deviceConfigSpec.Device.backing = New-Object VMware.Vim.VirtualEthernetCardNetworkBackingInfo
$deviceConfigSpec.device.backing.deviceName = $networkName
$connectable = New-Object VMware.Vim.VirtualDeviceConnectInfo
$connectable.MigrateConnect = "disconnect"
$deviceConfigSpec.Device.Connectable = $connectable
$locationSpec.DeviceChange += $deviceConfigSpec
}
$spec.Config = $config
$spec.Location = $locationSpec
$spec.Name = $DestinationVM
# SourceVM == Frozen
} else {
$spec = New-Object VMware.Vim.VirtualMachineInstantCloneSpec
$locationSpec = New-Object VMware.Vim.VirtualMachineRelocateSpec
$spec.Config = $config
$spec.Location = $locationSpec
$spec.Name = $DestinationVM
}
Write-Host "Creating Instant Clone $DestinationVM ..."
$task = $vm.ExtensionData.InstantClone_Task($spec)
$task1 = Get-Task -Id ("Task-$($task.value)")
$task1 | Wait-Task | Out-Null
}

46
Modules/NSXT/NSXT.psd1 Normal file
View File

@@ -0,0 +1,46 @@
@{
ModuleToProcess = 'NSXT.psm1'
ModuleVersion = '1.0.0.0'
GUID = 'c72f4e3d-5d1d-498f-ba86-6fa03e4ae6dd'
Author = 'William Lam'
CompanyName = 'primp-industries.com'
Copyright = '(c) 2017. All rights reserved.'
Description = 'Powershell Module for NSX-T REST API Functions'
PowerShellVersion = '5.0'
FunctionsToExport = 'Get-NSXTBGPNeighbors',
'Get-NSXTComputeManager',
'Get-NSXTController',
'Get-NSXTEdgeCluster',
'Get-NSXTFabricNode',
'Get-NSXTFabricVM',
'Get-NSXTFirewallRule',
'Get-NSXTForwardingTable',
'Get-NSXTIPPool',
'Get-NSXTLogicalRouter',
'Get-NSXTLogicalRouterPorts',
'Get-NSXTLogicalSwitch',
'Get-NSXTManager',
'Get-NSXTNetworkRoutes',
'Get-NSXTRoutingTable',
'Get-NSXTTraceFlow',
'Get-NSXTTraceFlowObservations',
'Get-NSXTTransportNode',
'Get-NSXTTransportZone',
'Get-NSXTClusterNode',
'Set-NSXTIPPool',
'Set-NSXTLogicalRouter',
'Set-NSXTLogicalSwitch',
'Set-NSXTTraceFlow',
'Get-NSXTIPAMIPBlock',
'Set-NSXTIPAMIPBlock',
'Remove-NSXTIPAMIPBlock'
PrivateData = @{
PSData = @{
Tags = @('NSX-T','REST')
LicenseUri = 'https://www.tldrlegal.com/l/mit'
ProjectUri = 'https://github.com/lamw/PowerCLI-Example-Scripts/tree/master/Modules/NSXT'
}
}
}

2104
Modules/NSXT/NSXT.psm1 Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,192 @@
function Get-VMEvcMode {
<#
.SYNOPSIS
Gathers information on the EVC status of a VM
.DESCRIPTION
Will provide the EVC status for the specified VM
.NOTES
Author: Kyle Ruddy, @kmruddy, thatcouldbeaproblem.com
.PARAMETER Name
VM name which the function should be ran against
.EXAMPLE
Get-VMEvcMode -Name vmName
Retreives the EVC status of the provided VM
#>
[CmdletBinding()]
param(
[Parameter(Mandatory=$true,Position=0,ValueFromPipelineByPropertyName=$true)]
$Name
)
Process {
$evVM = @()
if ($name -is [string]) {$evVM += Get-VM -Name $Name -ErrorAction SilentlyContinue}
elseif ($name -is [array]) {
if ($name[0] -is [string]) {
$name | foreach {
$evVM += Get-VM -Name $_ -ErrorAction SilentlyContinue
}
}
elseif ($name[0] -is [VMware.VimAutomation.ViCore.Impl.V1.Inventory.InventoryItemImpl]) {$evVM = $name}
}
elseif ($name -is [VMware.VimAutomation.ViCore.Impl.V1.Inventory.InventoryItemImpl]) {$evVM += $name}
if ($evVM -eq $null) {Write-Warning "No VMs found."}
else {
$output = @()
foreach ($v in $evVM) {
$report = "" | select Name,EVCMode
$report.Name = $v.Name
$report.EVCMode = $v.ExtensionData.Runtime.MinRequiredEVCModeKey
$output += $report
}
return $output
}
}
}
function Remove-VMEvcMode {
<#
.SYNOPSIS
Removes the EVC status of a VM
.DESCRIPTION
Will remove the EVC status for the specified VM
.NOTES
Author: Kyle Ruddy, @kmruddy, thatcouldbeaproblem.com
.PARAMETER Name
VM name which the function should be ran against
.EXAMPLE
Remove-VMEvcMode -Name vmName
Removes the EVC status of the provided VM
#>
[CmdletBinding()]
param(
[Parameter(Mandatory=$true,Position=0,ValueFromPipelineByPropertyName=$true)]
$Name
)
Process {
$evVM = @()
$updateVM = @()
if ($name -is [string]) {$evVM += Get-VM -Name $Name -ErrorAction SilentlyContinue}
elseif ($name -is [array]) {
if ($name[0] -is [string]) {
$name | foreach {
$evVM += Get-VM -Name $_ -ErrorAction SilentlyContinue
}
}
elseif ($name[0] -is [VMware.VimAutomation.ViCore.Impl.V1.Inventory.InventoryItemImpl]) {$evVM = $name}
}
elseif ($name -is [VMware.VimAutomation.ViCore.Impl.V1.Inventory.InventoryItemImpl]) {$evVM += $name}
if ($evVM -eq $null) {Write-Warning "No VMs found."}
else {
foreach ($v in $evVM) {
if (($v.HardwareVersion -ge 'vmx-14' -and $v.PowerState -eq 'PoweredOff') -or ($v.Version -ge 'v14' -and $v.PowerState -eq 'PoweredOff')) {
$v.ExtensionData.ApplyEvcModeVM_Task($null, $true) | Out-Null
$updateVM += $v.Name
}
else {Write-Warning $v.Name + " does not have the minimum requirements of being Hardware Version 14 and powered off."}
}
if ($updateVM) {
Start-Sleep -Seconds 2
Get-VMEvcMode -Name $updateVM
}
}
}
}
function Set-VMEvcMode {
<#
.SYNOPSIS
Configures the EVC status of a VM
.DESCRIPTION
Will configure the EVC status for the specified VM
.NOTES
Author: Kyle Ruddy, @kmruddy, thatcouldbeaproblem.com
.PARAMETER Name
VM name which the function should be ran against
.PARAMETER EvcMode
The EVC Mode key which should be set
.EXAMPLE
Set-VMEvcMode -Name vmName -EvcMode intel-sandybridge
Configures the EVC status of the provided VM to be 'intel-sandybridge'
#>
[CmdletBinding()]
param(
[Parameter(Mandatory=$true,Position=0,ValueFromPipelineByPropertyName=$true)]
$Name,
[Parameter(Mandatory=$true,Position=1)]
[ValidateSet("intel-merom","intel-penryn","intel-nehalem","intel-westmere","intel-sandybridge","intel-ivybridge","intel-haswell","intel-broadwell","intel-skylake","amd-rev-e","amd-rev-f","amd-greyhound-no3dnow","amd-greyhound","amd-bulldozer","amd-piledriver","amd-steamroller","amd-zen")]
$EvcMode
)
Process {
$evVM = @()
$updateVM = @()
if ($name -is [string]) {$evVM += Get-VM -Name $Name -ErrorAction SilentlyContinue}
elseif ($name -is [array]) {
if ($name[0] -is [string]) {
$name | foreach {
$evVM += Get-VM -Name $_ -ErrorAction SilentlyContinue
}
}
elseif ($name[0] -is [VMware.VimAutomation.ViCore.Impl.V1.Inventory.InventoryItemImpl]) {$evVM = $name}
}
elseif ($name -is [VMware.VimAutomation.ViCore.Impl.V1.Inventory.InventoryItemImpl]) {$evVM += $name}
if ($evVM -eq $null) {Write-Warning "No VMs found."}
else {
$si = Get-View ServiceInstance
$evcMask = $si.Capability.SupportedEvcMode | where-object {$_.key -eq $EvcMode} | select -ExpandProperty FeatureMask
foreach ($v in $evVM) {
if (($v.HardwareVersion -ge 'vmx-14' -and $v.PowerState -eq 'PoweredOff') -or ($v.Version -ge 'v14' -and $v.PowerState -eq 'PoweredOff')) {
$v.ExtensionData.ApplyEvcModeVM_Task($evcMask, $true) | Out-Null
$updateVM += $v.Name
}
else {Write-Warning $v.Name + " does not have the minimum requirements of being Hardware Version 14 and powered off."}
}
if ($updateVM) {
Start-Sleep -Seconds 2
Get-VMEvcMode -Name $updateVM
}
}
}
}

View File

@@ -0,0 +1,468 @@
Function New-PHAProvider {
<#
.NOTES
===========================================================================
Created by: William Lam
Organization: VMware
Blog: www.virtuallyghetto.com
Twitter: @lamw
===========================================================================
.DESCRIPTION
Function to register a new Proactive HA Provider with vCenter Server
.PARAMETER ProviderName
Name of ProactiveHA Provider
.PARAMETER ComponentType
Name of a supported ComponentType that ProactiveHA supports (Fan, Memory, Network, Power or Storage)
.PARAMETER ComponentDescription
Description of the health check for the given component
.PARAMETER ComponentId
Unique identifier for the given component within a ProactiveHA Provider
.EXAMPLE
New-PHAProvider -ProviderName "virtuallyGhetto" -ComponentType Power -ComponentDescription "Simulated ProactiveHA Provider" -ComponentId "Power"
#>
param(
[Parameter(Mandatory=$true)][String]$ProviderName,
[Parameter(Mandatory=$true)][ValidateSet("Fan","Memory","Network","Power","Storage")][String]$ComponentType,
[Parameter(Mandatory=$true)][String]$ComponentDescription,
[Parameter(Mandatory=$true)][String]$ComponentId
)
Write-Host -ForegroundColor Red "`n******************** DISCLAIMER ********************"
Write-Host -ForegroundColor Red "**** THIS IS NOT INTENDED FOR PRODUCTION USE ****"
Write-Host -ForegroundColor Red "**** LEARNING PURPOSES ONLY ****"
Write-Host -ForegroundColor Red "******************** DISCLAIMER ********************`n"
$healthManager = Get-View $global:DefaultVIServer.ExtensionData.Content.HealthUpdateManager
$healthInfo = [VMware.Vim.HealthUpdateInfo] @{
ComponentType = $ComponentType
description = $ComponentDescription
Id = $ComponentId
}
try {
Write-Host "`nRegistering new Proactive HA Provider $ProviderName ..."
$providerId = $healthManager.RegisterHealthUpdateProvider($ProviderName,$healthInfo)
} catch {
Write-host -ForegroundColor Red $Error[0].Exception
}
}
Function Get-PHAProvider {
<#
.NOTES
===========================================================================
Created by: William Lam
Organization: VMware
Blog: www.virtuallyghetto.com
Twitter: @lamw
===========================================================================
.DESCRIPTION
Function to return list of all Proactive HA Providers registered with vCenter Server
.EXAMPLE
Get-PHAProvider
#>
$healthManager = Get-View $global:DefaultVIServer.ExtensionData.Content.HealthUpdateManager
$healthProviderResults = @()
$hpIDs = $healthManager.QueryProviderList()
foreach ($hpID in $hpIDs) {
$hpName = $healthManager.QueryProviderName($hpID)
$hpConfig = $healthManager.QueryHealthUpdateInfos($hpID)
$hp = [pscustomobject] @{
ProviderName = $hpName
ProviderID = $hpID
ComponentType = $hpConfig.componentType
ComponentID = $hpConfig.id
Description = $hpConfig.description
}
$healthProviderResults+=$hp
}
$healthProviderResults
}
Function Remove-PHAProvider {
<#
.NOTES
===========================================================================
Created by: William Lam
Organization: VMware
Blog: www.virtuallyghetto.com
Twitter: @lamw
===========================================================================
.DESCRIPTION
Function to remove a registered Proactive HA Provider from vCenter Server
.PARAMETER ProviderId
The ProactiveHA provider ID (retrieved from Get-PHAProvider) to unregister
.EXAMPLE
Remove-PHAProvider -ProviderID "52 85 22 c2 f2 6a e7 b9-fc ff 63 9e 10 81 00 79"
#>
param(
[Parameter(Mandatory=$true)][String]$ProviderId
)
Write-Host -ForegroundColor Red "`n******************** DISCLAIMER ********************"
Write-Host -ForegroundColor Red "**** THIS IS NOT INTENDED FOR PRODUCTION USE ****"
Write-Host -ForegroundColor Red "**** LEARNING PURPOSES ONLY ****"
Write-Host -ForegroundColor Red "******************** DISCLAIMER ********************`n"
$healthManager = Get-View $global:DefaultVIServer.ExtensionData.Content.HealthUpdateManager
try {
Write-Host "`nUnregistering Proactive HA Provider $ProviderId ... "
$healthManager.UnregisterHealthUpdateProvider($providerId)
} catch {
if($Error[0].Exception.InnerException.MethodFault.getType().Name -eq "InvalidState") {
Write-host -ForegroundColor Red "The Proactive HA Provider is still in use, please disable it before unregistering"
} else {
Write-host -ForegroundColor Red $Error[0].Exception
}
}
}
Function Set-PHAConfig {
<#
.NOTES
===========================================================================
Created by: William Lam
Organization: VMware
Blog: www.virtuallyghetto.com
Twitter: @lamw
===========================================================================
.DESCRIPTION
Function to enable/disable Proactive HA for vSphere Cluster
.PARAMETER Cluster
Name of the vSphere Cluster to enable Proactive HA
.PARAMETER ProviderId
Proactive HA Provider ID to enable in vSphere Cluster
.PARAMETER ClusterMode
Whether Proactive HA should be "Automated" or "Manual" for actions it will take
.PARAMETER ModerateRemediation
Type of operation (Maintenance Mode or Quaratine Mode) to perform when a Moderate issue is observed
.PARAMETER SevereRemediation
Type of operation (Maintenance Mode or Quaratine Mode) to perform when a Severe issue is observed
.EXAMPLE
Set-PHAConfig -Cluster VSAN-Cluster -Enabled -ClusterMode Automated -ModerateRemediation QuarantineMode -SevereRemediation QuarantineMode -ProviderID "52 85 22 c2 f2 6a e7 b9-fc ff 63 9e 10 81 00 79"
.EXAMPLE
Set-PHAConfig -Cluster VSAN-Cluster -Disabled -ProviderID "52 85 22 c2 f2 6a e7 b9-fc ff 63 9e 10 81 00 79"
#>
param(
[Parameter(Mandatory=$true)][String]$ProviderId,
[Parameter(Mandatory=$true)][String]$Cluster,
[Parameter(Mandatory=$false)][ValidateSet("Automated","Manual")]$ClusterMode="Manual",
[Parameter(Mandatory=$false)][ValidateSet("MaintenanceMode","QuarantineMode")]$ModerateRemediation="QuarantineMode",
[Parameter(Mandatory=$false)][ValidateSet("MaintenanceMode","QuarantineMode")]$SevereRemediation="QuarantineMode",
[Switch]$Enabled,
[Switch]$Disabled
)
$ClusterView = Get-View -ViewType ClusterComputeResource -Property Name,Host,ConfigurationEx -Filter @{"Name" = $Cluster}
if($ClusterView -eq $null) {
Write-Host -ForegroundColor Red "Unable to find vSphere Cluster $cluster ..."
break
}
$vmhosts = $ClusterView.host
$healthManager = Get-View $global:DefaultVIServer.ExtensionData.Content.HealthUpdateManager
if($Enabled) {
try {
$entities = @()
foreach ($vmhost in $vmhosts) {
if(-not $healthManager.HasMonitoredEntity($ProviderId,$vmhost)) {
$entities += $vmhost
}
}
Write-Host "Enabling Proactive HA monitoring for all ESXi hosts in cluster ..."
$healthManager.AddMonitoredEntities($ProviderId,$entities)
} catch {
Write-host -ForegroundColor Red $Error[0].Exception
}
try {
$healthProviders = @()
# Make sure not to remove existing ProactiveHA providers
if($ClusterView.ConfigurationEx.InfraUpdateHaConfig.Providers -ne $null) {
$currentHPs = $ClusterView.ConfigurationEx.infraUpdateHaConfig.providers
foreach ($currentHP in $currentHPs) {
$healthProviders+=$currentHP
}
if(-not ($healthProviders -contains $ProviderID)) {
$healthProviders+=$ProviderId
}
} else {
$healthProviders+=$ProviderId
}
$PHASpec = [VMware.Vim.ClusterInfraUpdateHaConfigInfo] @{
enabled = $true
behavior = $ClusterMode
moderateRemediation = $ModerateRemediation
severeRemediation = $SevereRemediation
providers = $healthProviders
}
$spec = [VMware.Vim.ClusterConfigSpecEx] @{
infraUpdateHaConfig = $PHASpec
}
Write-Host "Enabling Proactive HA Provider $ProviderId on $Cluster ..."
$task = $ClusterView.ReconfigureComputeResource_Task($spec,$True)
$task1 = Get-Task -Id ("Task-$($task.value)")
$task1 | Wait-Task | Out-Null
} catch {
Write-host -ForegroundColor Red $Error[0].Exception
}
}
if($Disabled) {
foreach ($vmhost in $vmhosts) {
if($vmhost.runtime.inQuarantineMode) {
Write-Host -ForegroundColor Red $vmhost.name " is currently still in Quaratine Mode, please remediate this before disabling Proactive HA"
break
}
}
try {
$healthProviders = @()
# Make sure not to remove existing ProactiveHA providers
if($ClusterView.ConfigurationEx.InfraUpdateHaConfig.Providers -ne $null) {
$currentHPs = $ClusterView.ConfigurationEx.infraUpdateHaConfig.providers
foreach ($currentHP in $currentHPs) {
if($currentHP -ne $ProviderId) {
$healthProviders+=$currentHP
}
}
}
$PHASpec = [VMware.Vim.ClusterInfraUpdateHaConfigInfo] @{
enabled = $true
behavior = $ClusterMode
moderateRemediation = $ModerateRemediation
severeRemediation = $SevereRemediation
providers = $healthProviders
}
$spec = [VMware.Vim.ClusterConfigSpecEx] @{
infraUpdateHaConfig = $PHASpec
}
Write-Host "Disabling Proactive HA Provider $ProviderId on $Cluster ..."
$task = $ClusterView.ReconfigureComputeResource_Task($spec,$True)
$task1 = Get-Task -Id ("Task-$($task.value)")
$task1 | Wait-Task | Out-Null
} catch {
Write-host -ForegroundColor Red $Error[0].Exception
}
$ClusterView.UpdateViewData()
try {
$entities = @()
foreach ($vmhost in $vmhosts) {
if($healthManager.HasMonitoredEntity($ProviderId,$vmhost)) {
$entities += $vmhost
}
}
Write-Host "Disabling Proactive HA monitoring for all ESXi hosts in cluster ..."
$healthManager.RemoveMonitoredEntities($ProviderId,$entities)
} catch {
Write-host -ForegroundColor Red $Error[0].Exception
}
}
}
Function Get-PHAConfig {
<#
.NOTES
===========================================================================
Created by: William Lam
Organization: VMware
Blog: www.virtuallyghetto.com
Twitter: @lamw
===========================================================================
.DESCRIPTION
Function to retrieve Proactive HA configuration for a vSphere Cluster
.PARAMETER Cluster
Name of the vSphere Cluster to check Proactive HA configuration
.EXAMPLE
Get-PHAConfig -Cluster VSAN-Cluster
#>
param(
[Parameter(Mandatory=$true)][String]$Cluster
)
$ClusterView = Get-View -ViewType ClusterComputeResource -Property Name,ConfigurationEx -Filter @{"Name" = $Cluster}
if($ClusterView -eq $null) {
Write-Host -ForegroundColor Red "Unable to find vSphere Cluster $cluster ..."
break
}
if($ClusterView.ConfigurationEx.InfraUpdateHaConfig.Providers -ne $null) {
$healthManager = Get-View $global:DefaultVIServer.ExtensionData.Content.HealthUpdateManager
$phSettings = $ClusterView.ConfigurationEx.InfraUpdateHaConfig
$providers = $ClusterView.ConfigurationEx.InfraUpdateHaConfig.Providers
$healthProviders = @()
foreach ($provider in $providers) {
$providerName = $healthManager.QueryProviderName($provider)
$healthProviders+=$providerName
}
$pHAConfig = [pscustomobject] @{
Enabled = $phSettings.Enabled
ClusterMode = $phSettings.behavior
ModerateRemediation = $phSettings.ModerateRemediation
SevereRemediation = $phSettings.SevereRemediation
HealthProviders = $healthProviders
}
$pHAConfig
} else {
Write-Host "Proactive HA has not been configured on this vSphere Cluster"
}
}
Function Get-PHAHealth {
<#
.NOTES
===========================================================================
Created by: William Lam
Organization: VMware
Blog: www.virtuallyghetto.com
Twitter: @lamw
===========================================================================
.DESCRIPTION
Function to retrieve the Proactive HA health info for all ESXi hosts in vSphere Cluster
.PARAMETER Cluster
Name of the vSphere Cluster to check Proactive HA health information
.EXAMPLE
Get-PHAHealth -Cluster VSAN-Cluster
#>
param(
[Parameter(Mandatory=$true)][String]$Cluster
)
$ClusterView = Get-View -ViewType ClusterComputeResource -Property Name,ConfigurationEx -Filter @{"Name" = $Cluster}
if($ClusterView -eq $null) {
Write-Host -ForegroundColor Red "Unable to find vSphere Cluster $cluster ..."
break
}
if($ClusterView.ConfigurationEx.InfraUpdateHaConfig.Providers -ne $null) {
$healthManager = Get-View $global:DefaultVIServer.ExtensionData.Content.HealthUpdateManager
$providers = $ClusterView.ConfigurationEx.InfraUpdateHaConfig.Providers
foreach ($provider in $providers) {
$providerName = $healthManager.QueryProviderName($provider)
$healthUpdates = $healthManager.QueryHealthUpdates($provider)
$healthResults = @()
Write-Host -NoNewline -ForegroundColor Magenta "Health summary for Proactive HA Provider $providerName`:`n"
foreach ($healthUpdate in $healthUpdates) {
$vmhost = Get-View $healthUpdate.Entity
$hr = [PSCustomObject] @{
Entity = $vmhost.name
Status = $healthUpdate.status
HealthComponentId = $healthUpdate.HealthUpdateInfoId
HealthUpdateId = $healthUpdate.Id
Remediation = $healthUpdate.Remediation
}
$healthResults+=$hr
}
$healthResults
}
} else {
Write-Host "Proactive HA has not been configured on this vSphere Cluster"
}
}
Function New-PHASimulation {
<#
.NOTES
===========================================================================
Created by: William Lam
Organization: VMware
Blog: www.virtuallyghetto.com
Twitter: @lamw
===========================================================================
.DESCRIPTION
Function to return VCHA Configuration
.PARAMETER ProviderId
The Proactive HA Provider ID that you like to simulate a health update from
.PARAMETER EsxiHost
The name of ESXi host to update the health on
.PARAMETER Component
The name of the matching component ID from Proactive HA Provider to simulate a health update from
.PARAMETER HealthStatus
The health value (green, yellow or red) for the given simulated health Update
.PARAMETER Remediation
The remediation message associated with simulated health update
.EXAMPLE
New-PHASimulation -EsxiHost vesxi65-4.primp-industries.com -Component Power -HealthStatus green -Remediation "" -ProviderId "52 85 22 c2 f2 6a e7 b9-fc ff 63 9e 10 81 00 79"
.EXAMPLE
New-PHASimulation -EsxiHost vesxi65-4.primp-industries.com -Component Power -HealthStatus red -Remediation "Please replace my virtual PSU" -ProviderId "52 85 22 c2 f2 6a e7 b9-fc ff 63 9e 10 81 00 79"
#>
param(
[Parameter(Mandatory=$true)][String]$ProviderId,
[Parameter(Mandatory=$true)][String]$EsxiHost,
[Parameter(Mandatory=$true)][String]$Component,
[Parameter(Mandatory=$true)][ValidateSet("green","red","yellow")][String]$HealthStatus,
[Parameter(Mandatory=$false)][String]$Remediation
)
Write-Host -ForegroundColor Red "`n******************** DISCLAIMER ********************"
Write-Host -ForegroundColor Red "**** THIS IS NOT INTENDED FOR PRODUCTION USE ****"
Write-Host -ForegroundColor Red "**** LEARNING PURPOSES ONLY ****"
Write-Host -ForegroundColor Red "******************** DISCLAIMER ********************`n"
$vmhost = Get-View -ViewType HostSystem -Property Name -Filter @{"name" = $EsxiHost}
if($vmhost -eq $null) {
Write-Host -ForegroundColor Red "`nUnable to find ESXi host $EsxiHost ..."
break
}
$healthManager = Get-View $global:DefaultVIServer.ExtensionData.Content.HealthUpdateManager
# Randomly generating an ID for Health Update
# In general, you would want to generate a specific ID
# which can be referenced between ProactiveHA Provider
# and VMware logs for troubleshooting purposes
$HealthUpdateID = "vghetto-" + (Get-Random -Minimum 1 -Maximum 100000)
# All other Health Status can have a remediation message
# but for green, it must be an empty string or API call will fail
if($HealthStatus -eq "green") {
$Remediation = ""
}
$healthUpdate = [VMware.Vim.HealthUpdate] @{
Entity = $vmhost.moref
HealthUpdateInfoId = $Component
Id = $HealthUpdateId
Status = $HealthStatus
Remediation = $Remediation
}
try {
Write-Host "`nSimulating Proactive HA Health Update to ..."
Write-Host "`tHost: $EsxiHost "
Write-Host -NoNewline "`tStatus: "
Write-Host -ForegroundColor $HealthStatus "$HealthStatus"
Write-Host "`tRemediation Messsage: $Remediation"
$healthManager.PostHealthUpdates($providerId,$healthUpdate)
} catch {
Write-host -ForegroundColor Red $Error[0].Exception
}
}

1
Modules/SRM/.gitattributes vendored Normal file
View File

@@ -0,0 +1 @@
*.psd1 diff

1
Modules/SRM/.gitignore vendored Normal file
View File

@@ -0,0 +1 @@
*.zip

View File

@@ -0,0 +1,167 @@
# Depends on SRM Helper Methods - https://github.com/benmeadowcroft/SRM-Cmdlets
# It is assumed that the connection to VC and SRM Server have already been made
Function Get-SrmConfigReportSite {
Param(
[VMware.VimAutomation.Srm.Types.V1.SrmServer] $SrmServer
)
Get-SrmServer $SrmServer |
Format-Table -Wrap -AutoSize @{Label="SRM Site Name"; Expression={$_.ExtensionData.GetSiteName()} },
@{Label="SRM Host"; Expression={$_.Name} },
@{Label="SRM Port"; Expression={$_.Port} },
@{Label="Version"; Expression={$_.Version} },
@{Label="Build"; Expression={$_.Build} },
@{Label="SRM Peer Site Name"; Expression={$_.ExtensionData.GetPairedSite().Name} }
}
Function Get-SrmConfigReportPlan {
Param(
[VMware.VimAutomation.Srm.Types.V1.SrmServer] $SrmServer
)
Get-SrmRecoveryPlan -SrmServer $SrmServer | %{
$rp = $_
$rpinfo = $rp.GetInfo()
$peerState = $rp.GetPeer().State
$pgs = Get-SrmProtectionGroup -RecoveryPlan $rp
$pgnames = $pgs | %{ $_.GetInfo().Name }
$output = "" | select plan, state, peerState, groups
$output.plan = $rpinfo.Name
$output.state = $rpinfo.State
$output.peerState = $peerState
if ($pgnames) {
$output.groups = [string]::Join(",`r`n", $pgnames)
} else {
$output.groups = "NONE"
}
$output
} | Format-Table -Wrap -AutoSize @{Label="Recovery Plan Name"; Expression={$_.plan} },
@{Label="Recovery State"; Expression={$_.state} },
@{Label="Peer Recovery State"; Expression={$_.peerState} },
@{Label="Protection Groups"; Expression={$_.groups}}
}
Function Get-SrmConfigReportProtectionGroup {
Param(
[VMware.VimAutomation.Srm.Types.V1.SrmServer] $SrmServer
)
Get-SrmProtectionGroup -SrmServer $SrmServer | %{
$pg = $_
$pginfo = $pg.GetInfo()
$pgstate = $pg.GetProtectionState()
$peerState = $pg.GetPeer().State
$rps = Get-SrmRecoveryPlan -ProtectionGroup $pg
$rpnames = $rps | %{ $_.GetInfo().Name }
$output = "" | select name, type, state, peerState, plans
$output.name = $pginfo.Name
$output.type = $pginfo.Type
$output.state = $pgstate
$output.peerState = $peerState
if ($rpnames) {
$output.plans = [string]::Join(",`r`n", $rpnames)
} else {
$output.plans = "NONE"
}
$output
} | Format-Table -Wrap -AutoSize @{Label="Protection Group Name"; Expression={$_.name} },
@{Label="Type"; Expression={$_.type} },
@{Label="Protection State"; Expression={$_.state} },
@{Label="Peer Protection State"; Expression={$_.peerState} },
@{Label="Recovery Plans"; Expression={$_.plans} }
}
Function Get-SrmConfigReportProtectedDatastore {
Param(
[VMware.VimAutomation.Srm.Types.V1.SrmServer] $SrmServer
)
Get-SrmProtectionGroup -SrmServer $SrmServer -Type "san" | %{
$pg = $_
$pginfo = $pg.GetInfo()
$pds = Get-SrmProtectedDatastore -ProtectionGroup $pg
$pds | %{
$pd = $_
$output = "" | select datacenter, group, name, capacity, free
$output.datacenter = $pd.Datacenter.Name
$output.group = $pginfo.Name
$output.name = $pd.Name
$output.capacity = $pd.CapacityGB
$output.free = $pd.FreeSpaceGB
$output
}
} | Format-Table -Wrap -AutoSize -GroupBy "datacenter" @{Label="Datastore Name"; Expression={$_.name} },
@{Label="Capacity GB"; Expression={$_.capacity} },
@{Label="Free GB"; Expression={$_.free} },
@{Label="Protection Group"; Expression={$_.group} }
}
Function Get-SrmConfigReportProtectedVm {
Param(
[VMware.VimAutomation.Srm.Types.V1.SrmServer] $SrmServer
)
$srmversion = Get-SrmServerVersion -SrmServer $SrmServer
$srmMajorVersion, $srmMinorVersion = $srmversion -split "\."
Get-SrmProtectionGroup -SrmServer $SrmServer | %{
$pg = $_
$pginfo = $pg.GetInfo()
$pvms = Get-SrmProtectedVM -ProtectionGroup $pg
$rps = Get-SrmRecoveryPlan -ProtectionGroup $pg
$rpnames = $rps | %{ $_.GetInfo().Name }
$pvms | %{
$pvm = $_
if ($srmMajorVersion -ge 6 -or ($srmMajorVersion -eq 5 -and $srmMinorVersion -eq 8)) {
$rs = $rps | Select -First 1 | %{ $_.GetRecoverySettings($pvm.Vm.MoRef) }
}
$output = "" | select group, name, moRef, needsConfiguration, state, plans, priority, finalPowerState, preCallouts, postCallouts
$output.group = $pginfo.Name
$output.name = $pvm.Vm.Name
$output.moRef = $pvm.Vm.MoRef # this is necessary in case we can't retrieve the name when VC is unavailable
$output.needsConfiguration = $pvm.NeedsConfiguration
$output.state = $pvm.State
$output.plans = [string]::Join(",`r`n", $rpnames)
if ($rs) {
$output.priority = $rs.RecoveryPriority
$output.finalPowerState = $rs.FinalPowerState
$output.preCallouts = $rs.PrePowerOnCallouts.Count
$output.postCallouts = $rs.PostPowerOnCallouts.Count
}
$output
}
} | Format-Table -Wrap -AutoSize @{Label="VM Name"; Expression={$_.name} },
@{Label="VM MoRef"; Expression={$_.moRef} },
@{Label="Needs Config"; Expression={$_.needsConfiguration} },
@{Label="VM Protection State"; Expression={$_.state} },
@{Label="Protection Group"; Expression={$_.group} },
@{Label="Recovery Plans"; Expression={$_.plans} },
@{Label="Recovery Priority"; Expression={$_.priority} },
@{Label="Final Power State"; Expression={$_.finalPowerState} },
@{Label="Pre-PowerOn Callouts"; Expression={$_.preCallouts} },
@{Label="Post-PowerOn Callouts"; Expression={$_.postCallouts} }
}
Function Get-SrmConfigReport {
Param(
[VMware.VimAutomation.Srm.Types.V1.SrmServer] $SrmServer
)
Get-SrmConfigReportSite -SrmServer $SrmServer
Get-SrmConfigReportPlan -SrmServer $SrmServer
Get-SrmConfigReportProtectionGroup -SrmServer $SrmServer
Get-SrmConfigReportProtectedDatastore -SrmServer $SrmServer
Get-SrmConfigReportProtectedVm -SrmServer $SrmServer
}

View File

@@ -0,0 +1,34 @@
# Depends on SRM Helper Methods - https://github.com/benmeadowcroft/SRM-Cmdlets
# It is assumed that the connections to active VC and SRM Server have already been made
Import-Module Meadowcroft.SRM -Prefix Srm
$TagCategoryName = 'Meadowcroft.SRM.VM'
$TagCategoryDescription = 'Tag category for tagging VMs with SRM state'
# If the tag category doesn't exist, create it and the relevant tags
$TagCategory = Get-TagCategory -Name $TagCategoryName -ErrorAction SilentlyContinue
if (-Not $TagCategory) {
Write-Output "Creating Tag Category $TagCategoryName"
$TagCategory = New-TagCategory -Name $TagCategoryName -Description $TagCategoryDescription -EntityType 'VirtualMachine'
Write-Output "Creating Tag SrmProtectedVm"
New-Tag -Name 'SrmProtectedVm' -Category $TagCategory -Description "VM protected by VMware SRM"
Write-Output "Creating Tag SrmTestVm"
New-Tag -Name 'SrmTestVm' -Category $TagCategory -Description "Test VM instantiated by VMware SRM"
Write-Output "Creating Tag SrmPlaceholderVm"
New-Tag -Name 'SrmPlaceholderVm' -Category $TagCategory -Description "Placeholder VM used by VMware SRM"
}
$protectedVmTag = Get-Tag -Name 'SrmProtectedVm' -Category $TagCategory
$testVmTag = Get-Tag -Name 'SrmTestVm' -Category $TagCategory
$placeholderVmTag = Get-Tag -Name 'SrmPlaceholderVm' -Category $TagCategory
# Assign protected tag to a VM, use ready state to get "local" protected VMs
Get-SrmProtectedVM -State Ready | %{ New-TagAssignment -Tag $protectedVmTag -Entity $(Get-VIObjectByVIView $_.Vm) | Out-Null }
# Assign test tag to a VM
Get-SrmTestVM | %{ New-TagAssignment -Tag $testVmTag -Entity $_ | Out-Null }
# Assign placeholder tag to a VM
Get-SrmPlaceholderVM | %{ New-TagAssignment -Tag $placeholderVmTag -Entity $_ | Out-Null }

74
Modules/SRM/LICENSE.txt Normal file
View File

@@ -0,0 +1,74 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files.
"Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions:
(a) You must give any other recipients of the Work or Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License.
You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "[]" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives.
Copyright [yyyy] [name of copyright owner]
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied.
See the License for the specific language governing permissions and
limitations under the License.

View File

@@ -0,0 +1,422 @@
# SRM Helper Methods - https://github.com/benmeadowcroft/SRM-Cmdlets
<#
.SYNOPSIS
Get the subset of protection groups matching the input criteria
.PARAMETER Name
Return protection groups matching the specified name
.PARAMETER Type
Return protection groups matching the specified protection group
type. For SRM 5.0-5.5 this is either 'san' for protection groups
consisting of a set of replicated datastores or 'vr' for vSphere
Replication based protection groups.
.PARAMETER RecoveryPlan
Return protection groups associated with a particular recovery
plan
.PARAMETER SrmServer
the SRM server to use for this operation.
#>
Function Get-ProtectionGroup {
[cmdletbinding()]
Param(
[Parameter(position=1)][string] $Name,
[string] $Type,
[Parameter (ValueFromPipeline=$true)][VMware.VimAutomation.Srm.Views.SrmRecoveryPlan[]] $RecoveryPlan,
[VMware.VimAutomation.Srm.Types.V1.SrmServer] $SrmServer
)
begin {
$api = Get-ServerApiEndpoint -SrmServer $SrmServer
$pgs = @()
}
process {
if ($RecoveryPlan) {
foreach ($rp in $RecoveryPlan) {
$pgs += $RecoveryPlan.GetInfo().ProtectionGroups
}
$pgs = Select_UniqueByMoRef($pgs)
} else {
$pgs += $api.Protection.ListProtectionGroups()
}
}
end {
$pgs | ForEach-Object {
$pg = $_
$pgi = $pg.GetInfo()
$selected = (-not $Name -or ($Name -eq $pgi.Name)) -and (-not $Type -or ($Type -eq $pgi.Type))
if ($selected) {
Add-Member -InputObject $pg -MemberType NoteProperty -Name "Name" -Value $pgi.Name
$pg
}
}
}
}
<#
.SYNOPSIS
Get the subset of protected VMs matching the input criteria
.PARAMETER Name
Return protected VMs matching the specified name
.PARAMETER State
Return protected VMs matching the specified state. For protected
VMs on the protected site this is usually 'ready', for
placeholder VMs this is 'shadowing'
.PARAMETER ProtectionGroup
Return protected VMs associated with particular protection
groups
#>
Function Get-ProtectedVM {
[cmdletbinding()]
Param(
[Parameter(position=1)][string] $Name,
[VMware.VimAutomation.Srm.Views.SrmProtectionGroupProtectionState] $State,
[VMware.VimAutomation.Srm.Views.SrmProtectionGroupProtectionState] $PeerState,
[switch] $ConfiguredOnly,
[switch] $UnconfiguredOnly,
[Parameter (ValueFromPipeline=$true)][VMware.VimAutomation.Srm.Views.SrmProtectionGroup[]] $ProtectionGroup,
[Parameter (ValueFromPipeline=$true)][VMware.VimAutomation.Srm.Views.SrmRecoveryPlan[]] $RecoveryPlan,
[string] $ProtectionGroupName,
[VMware.VimAutomation.Srm.Types.V1.SrmServer] $SrmServer
)
if ($null -eq $ProtectionGroup) {
$ProtectionGroup = Get-ProtectionGroup -Name $ProtectionGroupName -RecoveryPlan $RecoveryPlan -SrmServer $SrmServer
}
$ProtectionGroup | ForEach-Object {
$pg = $_
$pg.ListProtectedVms() | ForEach-Object {
# try and update the view data for the protected VM
try {
$_.Vm.UpdateViewData()
} catch {
Write-Error $_
} finally {
$_
}
} | Where-object { -not $Name -or ($Name -eq $_.Vm.Name) } |
where-object { -not $State -or ($State -eq $_.State) } |
where-object { -not $PeerState -or ($PeerState -eq $_.PeerState) } |
where-object { ($ConfiguredOnly -and $_.NeedsConfiguration -eq $false) -or ($UnconfiguredOnly -and $_.NeedsConfiguration -eq $true) -or (-not $ConfiguredOnly -and -not $UnconfiguredOnly) }
}
}
<#
.SYNOPSIS
Get the unprotected VMs that are associated with a protection group
.PARAMETER ProtectionGroup
Return unprotected VMs associated with particular protection
groups. For VR protection groups this is VMs that are associated
with the PG but not configured, For ABR protection groups this is
VMs on replicated datastores associated with the group that are not
configured.
#>
Function Get-UnProtectedVM {
[cmdletbinding()]
Param(
[Parameter (ValueFromPipeline=$true)][VMware.VimAutomation.Srm.Views.SrmProtectionGroup[]] $ProtectionGroup,
[Parameter (ValueFromPipeline=$true)][VMware.VimAutomation.Srm.Views.SrmRecoveryPlan[]] $RecoveryPlan,
[string] $ProtectionGroupName,
[VMware.VimAutomation.Srm.Types.V1.SrmServer] $SrmServer
)
if ($null -eq $ProtectionGroup) {
$ProtectionGroup = Get-ProtectionGroup -Name $ProtectionGroupName -RecoveryPlan $RecoveryPlan -SrmServer $SrmServer
}
$associatedVMs = @()
$protectedVmRefs = @()
$ProtectionGroup | ForEach-Object {
$pg = $_
# For VR listAssociatedVms to get list of VMs
if ($pg.GetInfo().Type -eq 'vr') {
$associatedVMs += @($pg.ListAssociatedVms() | Get-VIObjectByVIView)
}
# TODO test this: For ABR get VMs on GetProtectedDatastore
if ($pg.GetInfo().Type -eq 'san') {
$pds = @(Get-ProtectedDatastore -ProtectionGroup $pg)
$pds | ForEach-Object {
$ds = Get-Datastore -id $_.MoRef
$associatedVMs += @(Get-VM -Datastore $ds)
}
}
# get protected VMs
$protectedVmRefs += @(Get-ProtectedVM -ProtectionGroup $pg | ForEach-Object { $_.Vm.MoRef } | Select-Object -Unique)
}
# get associated but unprotected VMs
$associatedVMs | Where-Object { $protectedVmRefs -notcontains $_.ExtensionData.MoRef }
}
#Untested as I don't have ABR setup in my lab yet
<#
.SYNOPSIS
Get the subset of protected Datastores matching the input criteria
.PARAMETER ProtectionGroup
Return protected datastores associated with particular protection
groups
#>
Function Get-ProtectedDatastore {
[cmdletbinding()]
Param(
[Parameter (ValueFromPipeline=$true)][VMware.VimAutomation.Srm.Views.SrmProtectionGroup[]] $ProtectionGroup,
[Parameter (ValueFromPipeline=$true)][VMware.VimAutomation.Srm.Views.SrmRecoveryPlan[]] $RecoveryPlan,
[string] $ProtectionGroupName,
[VMware.VimAutomation.Srm.Types.V1.SrmServer] $SrmServer
)
if (-not $ProtectionGroup) {
$ProtectionGroup = Get-ProtectionGroup -Name $ProtectionGroupName -RecoveryPlan $RecoveryPlan -SrmServer $SrmServer
}
$ProtectionGroup | ForEach-Object {
$pg = $_
if ($pg.GetInfo().Type -eq 'san') { # only supported for array based replication datastores
$pg.ListProtectedDatastores()
}
}
}
#Untested as I don't have ABR setup in my lab yet
<#
.SYNOPSIS
Get the replicated datastores that aren't associated with a protection group.
#>
Function Get-ReplicatedDatastore {
[cmdletbinding()]
Param(
[VMware.VimAutomation.Srm.Types.V1.SrmServer] $SrmServer
)
$api = Get-ServerApiEndpoint -SrmServer $SrmServer
$api.Protection.ListUnassignedReplicatedDatastores()
}
<#
.SYNOPSIS
Protect a VM using SRM
.PARAMETER ProtectionGroup
The protection group that this VM will belong to
.PARAMETER Vm
The virtual machine to protect
#>
Function Protect-VM {
[cmdletbinding()]
Param(
[Parameter (Mandatory=$true)][VMware.VimAutomation.Srm.Views.SrmProtectionGroup] $ProtectionGroup,
[Parameter (ValueFromPipeline=$true)][VMware.VimAutomation.ViCore.Types.V1.Inventory.VirtualMachine] $Vm,
[Parameter (ValueFromPipeline=$true)][VMware.Vim.VirtualMachine] $VmView
)
$moRef = Get_MoRefFromVmObj -Vm $Vm -VmView $VmView
$pgi = $ProtectionGroup.GetInfo()
#TODO query protection status first
if ($moRef) {
if ($pgi.Type -eq 'vr') {
$ProtectionGroup.AssociateVms(@($moRef))
}
$protectionSpec = New-Object VMware.VimAutomation.Srm.Views.SrmProtectionGroupVmProtectionSpec
$protectionSpec.Vm = $moRef
$protectTask = $ProtectionGroup.ProtectVms($protectionSpec)
while(-not $protectTask.IsComplete()) { Start-Sleep -Seconds 1 }
$protectTask.GetResult()
} else {
throw "Can't protect the VM, no MoRef found."
}
}
<#
.SYNOPSIS
Unprotect a VM using SRM
.PARAMETER ProtectionGroup
The protection group that this VM will be removed from
.PARAMETER Vm
The virtual machine to unprotect
#>
Function Unprotect-VM {
[cmdletbinding()]
Param(
[Parameter (Mandatory=$true)][VMware.VimAutomation.Srm.Views.SrmProtectionGroup] $ProtectionGroup,
[Parameter (ValueFromPipeline=$true)][VMware.VimAutomation.ViCore.Types.V1.Inventory.VirtualMachine] $Vm,
[Parameter (ValueFromPipeline=$true)][VMware.Vim.VirtualMachine] $VmView,
[Parameter (ValueFromPipeline=$true)][VMware.VimAutomation.Srm.Views.SrmProtectionGroupProtectedVm] $ProtectedVm
)
$moRef = Get_MoRefFromVmObj -Vm $Vm -VmView $VmView -ProtectedVm $ProtectedVm
$pgi = $ProtectionGroup.GetInfo()
$protectTask = $ProtectionGroup.UnprotectVms($moRef)
while(-not $protectTask.IsComplete()) { Start-Sleep -Seconds 1 }
if ($pgi.Type -eq 'vr') {
$ProtectionGroup.UnassociateVms(@($moRef))
}
$protectTask.GetResult()
}
<#
.SYNOPSIS
Get a protection group folder
.PARAMETER SrmServer
The SRM Server to query for the protection group folder
#>
Function Get-ProtectionGroupFolder {
[cmdletbinding()]
Param(
[VMware.VimAutomation.Srm.Types.V1.SrmServer] $SrmServer
)
$api = Get-ServerApiEndpoint -SrmServer $SrmServer
$folder = $api.Protection.GetProtectionGroupRootFolder()
return $folder
}
<#
.SYNOPSIS
Create a new protection group
.PARAMETER Name
The name of the protection group
.PARAMETER Description
Description of the protection group
.PARAMETER Folder
The protection group folder in which to create the new protection group
.PARAMETER ArrayReplication
Set if protection group is for replicating VMs using Array based replication
.PARAMETER vSphereReplication
Set if protection group is for replicating VMs with vSphere Replication
.PARAMETER VMs
For vSphere Replication based protection, the VMs to add to the replication
group. These should already be replicated.
.PARAMETER VMViews
For vSphere Replication based protection, the VMs to add to the replication
group. These should already be replicated.
.PARAMETER SrmServer
The SRM Server to perform the operation against
#>
Function New-ProtectionGroup {
[cmdletbinding(DefaultParameterSetName="VR", SupportsShouldProcess=$True, ConfirmImpact="Medium")]
[OutputType([VMware.VimAutomation.Srm.Views.SrmProtectionGroup])]
Param(
[Parameter (Mandatory=$true)] $Name,
$Description,
[VMware.VimAutomation.Srm.Views.SrmProtectionGroupFolder] $Folder,
[Parameter (ParameterSetName="ABR", Mandatory=$true)][switch] $ArrayReplication,
[Parameter (ValueFromPipeline=$true, ParameterSetName="ABR")][VMware.VimAutomation.ViCore.Types.V1.DatastoreManagement.Datastore[]] $Datastores,
[Parameter (ValueFromPipeline=$true, ParameterSetName="ABR")][VMware.Vim.Datastore[]] $DatastoreViews,
[Parameter (ParameterSetName="VR", Mandatory=$true)][switch] $vSphereReplication,
[Parameter (ValueFromPipeline=$true, ParameterSetName="VR")][VMware.VimAutomation.ViCore.Types.V1.Inventory.VirtualMachine[]] $VMs,
[Parameter (ValueFromPipeline=$true, ParameterSetName="VR")][VMware.Vim.VirtualMachine[]] $VMViews,
[VMware.VimAutomation.Srm.Types.V1.SrmServer] $SrmServer
)
$api = Get-ServerApiEndpoint $SrmServer
[VMware.VimAutomation.Srm.Views.SrmCreateProtectionGroupTask] $task = $null
#get root folder if this wasn't specified as a parameter
if(-not $Folder) {
$Folder = Get-ProtectionGroupFolder -SrmServer $SrmServer
}
if ($vSphereReplication) {
#create list of managed object references from VM and/or VM view arrays
[VMware.Vim.ManagedObjectReference[]]$moRefs = @()
foreach ($vm in $VMs) {
$moRefs += Get_MoRefFromVmObj -Vm $Vm
}
foreach ($VmView in $VMViews) {
$moRefs += Get_MoRefFromVmObj -VmView $VmView
}
if ($pscmdlet.ShouldProcess($Name, "New")) {
$task = $api.Protection.CreateHbrProtectionGroup($Folder.MoRef, $Name, $Description, $moRefs)
}
} elseif ($ArrayReplication) {
#create list of managed object references from VM and/or VM view arrays
$moRefs = @()
foreach ($ds in $Datastores) {
$moRefs += $ds.ExtensionData.MoRef
}
foreach ($DsView in $DatastoreViews) {
$moRefs += $DsView.MoRef
}
if ($pscmdlet.ShouldProcess($Name, "New")) {
$task = $api.Protection.CreateAbrProtectionGroup($Folder.MoRef, $Name, $Description, $moRefs)
}
} else {
throw "Undetermined protection group type"
}
# Complete task
while(-not $task.IsCreateProtectionGroupComplete()) { Start-Sleep -Seconds 1 }
# Retrieve the protection group, and protect associated VMs
$pg = $task.GetNewProtectionGroup()
if ($pg) {
$unProtectedVMs = Get-UnProtectedVM -ProtectionGroup $pg
$unProtectedVMs | Protect-VM -ProtectionGroup $pg
}
return $pg
}
<#
.SYNOPSIS
Delete a protection group
.PARAMETER ProtectionGroup
The protection group to remove
.PARAMETER SrmServer
The SRM Server to perform the operation against
#>
Function Remove-ProtectionGroup {
[cmdletbinding(SupportsShouldProcess=$True, ConfirmImpact="High")]
[OutputType([VMware.VimAutomation.Srm.Views.RemoveProtectionGroupTask])]
Param(
[Parameter (Mandatory=$true, ValueFromPipeline=$true)][VMware.VimAutomation.Srm.Views.SrmProtectionGroup] $ProtectionGroup,
[VMware.VimAutomation.Srm.Types.V1.SrmServer] $SrmServer
)
$api = Get-ServerApiEndpoint $SrmServer
[VMware.VimAutomation.Srm.Views.RemoveProtectionGroupTask] $task = $null
$pginfo = $ProtectionGroup.GetInfo()
if ($pscmdlet.ShouldProcess($pginfo.Name, "Remove")) {
$task = $api.Protection.RemoveProtectionGroup($ProtectionGroup.MoRef)
}
return $task
}

View File

@@ -0,0 +1,556 @@
# SRM Helper Methods - https://github.com/benmeadowcroft/SRM-Cmdlets
<#
.SYNOPSIS
Get the subset of recovery plans matching the input criteria
.PARAMETER Name
Return recovery plans matching the specified name
.PARAMETER ProtectionGroup
Return recovery plans associated with particular protection
groups
#>
Function Get-RecoveryPlan {
[cmdletbinding()]
Param(
[Parameter(position=1)][string] $Name,
[Parameter (ValueFromPipeline=$true)][VMware.VimAutomation.Srm.Views.SrmProtectionGroup[]] $ProtectionGroup,
[VMware.VimAutomation.Srm.Types.V1.SrmServer] $SrmServer
)
begin {
$api = Get-ServerApiEndpoint -SrmServer $SrmServer
$rps = @()
}
process {
if ($ProtectionGroup) {
foreach ($pg in $ProtectionGroup) {
$rps += $pg.ListRecoveryPlans()
}
$rps = Select_UniqueByMoRef($rps)
} else {
$rps += $api.Recovery.ListPlans()
}
}
end {
$rps | ForEach-Object {
$rp = $_
$rpi = $rp.GetInfo()
$selected = (-not $Name -or ($Name -eq $rpi.Name))
if ($selected) {
Add-Member -InputObject $rp -MemberType NoteProperty -Name "Name" -Value $rpi.Name
$rp
}
}
}
}
<#
.SYNOPSIS
Start a Recovery Plan action like test, recovery, cleanup, etc.
.PARAMETER RecoveryPlan
The recovery plan to start
.PARAMETER RecoveryMode
The recovery mode to invoke on the plan. May be one of "Test", "Cleanup", "Failover", "Migrate", "Reprotect"
#>
Function Start-RecoveryPlan {
[cmdletbinding(SupportsShouldProcess=$True, ConfirmImpact="High")]
Param(
[Parameter (Mandatory=$true, ValueFromPipeline=$true, Position=1)][VMware.VimAutomation.Srm.Views.SrmRecoveryPlan] $RecoveryPlan,
[VMware.VimAutomation.Srm.Views.SrmRecoveryPlanRecoveryMode] $RecoveryMode = [VMware.VimAutomation.Srm.Views.SrmRecoveryPlanRecoveryMode]::Test,
[bool] $SyncData = $True
)
# Validate with informative error messages
$rpinfo = $RecoveryPlan.GetInfo()
# Create recovery options
$rpOpt = New-Object VMware.VimAutomation.Srm.Views.SrmRecoveryOptions
$rpOpt.SyncData = $SyncData
# Prompt the user to confirm they want to execute the action
if ($pscmdlet.ShouldProcess($rpinfo.Name, $RecoveryMode)) {
if ($rpinfo.State -eq 'Protecting') {
throw "This recovery plan action needs to be initiated from the other SRM instance"
}
$RecoveryPlan.Start($RecoveryMode, $rpOpt)
}
}
<#
.SYNOPSIS
Stop a running Recovery Plan action.
.PARAMETER RecoveryPlan
The recovery plan to stop
#>
Function Stop-RecoveryPlan {
[cmdletbinding(SupportsShouldProcess=$True,ConfirmImpact="High")]
Param(
[Parameter (Mandatory=$true, ValueFromPipeline=$true, Position=1)][VMware.VimAutomation.Srm.Views.SrmRecoveryPlan] $RecoveryPlan
)
# Validate with informative error messages
$rpinfo = $RecoveryPlan.GetInfo()
# Prompt the user to confirm they want to cancel the running action
if ($pscmdlet.ShouldProcess($rpinfo.Name, 'Cancel')) {
$RecoveryPlan.Cancel()
}
}
<#
.SYNOPSIS
Retrieve the historical results of a recovery plan
.PARAMETER RecoveryPlan
The recovery plan to retrieve the history for
#>
Function Get-RecoveryPlanResult {
[cmdletbinding()]
Param(
[Parameter (Mandatory=$true, ValueFromPipeline=$true, Position=1)][VMware.VimAutomation.Srm.Views.SrmRecoveryPlan] $RecoveryPlan,
[VMware.VimAutomation.Srm.Views.SrmRecoveryPlanRecoveryMode] $RecoveryMode,
[VMware.VimAutomation.Srm.Views.SrmRecoveryResultResultState] $ResultState,
[DateTime] $StartedAfter,
[DateTime] $startedBefore,
[VMware.VimAutomation.Srm.Types.V1.SrmServer] $SrmServer
)
$api = Get-ServerApiEndpoint -SrmServer $SrmServer
# Get the history objects
$history = $api.Recovery.GetHistory($RecoveryPlan.MoRef)
$resultCount = $history.GetResultCount()
if ($resultCount -gt 0) {
$results = $history.GetRecoveryResult($resultCount)
$results |
Where-Object { -not $RecoveryMode -or $_.RunMode -eq $RecoveryMode } |
Where-Object { -not $ResultState -or $_.ResultState -eq $ResultState } |
Where-Object { $null -eq $StartedAfter -or $_.StartTime -gt $StartedAfter } |
Where-Object { $null -eq $StartedBefore -or $_.StartTime -lt $StartedBefore }
}
}
<#
.SYNOPSIS
Exports a recovery plan result object to XML format
.PARAMETER RecoveryPlanResult
The recovery plan result to export
#>
Function Export-RecoveryPlanResultAsXml {
[cmdletbinding()]
[OutputType([xml])]
Param(
[Parameter (Mandatory=$true, ValueFromPipeline=$true, Position=1)][VMware.VimAutomation.Srm.Views.SrmRecoveryResult] $RecoveryPlanResult,
[VMware.VimAutomation.Srm.Types.V1.SrmServer] $SrmServer
)
$api = Get-ServerApiEndpoint -SrmServer $SrmServer
$RecoveryPlan = $RecoveryPlanResult.Plan
$history = $api.Recovery.GetHistory($RecoveryPlan.MoRef)
$lines = $history.GetResultLength($RecoveryPlanResult.Key)
[xml] $history.RetrieveStatus($RecoveryPlanResult.Key, 0, $lines)
}
<#
.SYNOPSIS
Add a protection group to a recovery plan. This requires SRM 5.8 or later.
.PARAMETER RecoveryPlan
The recovery plan the protection group will be associated with
.PARAMETER ProtectionGroup
The protection group to associate with the recovery plan
#>
Function Add-ProtectionGroupToRecoveryPlan {
[cmdletbinding()]
Param(
[Parameter (Mandatory=$true, Position=1)][VMware.VimAutomation.Srm.Views.SrmRecoveryPlan] $RecoveryPlan,
[Parameter (Mandatory=$true, ValueFromPipeline=$true, Position=2)][VMware.VimAutomation.Srm.Views.SrmProtectionGroup] $ProtectionGroup
)
if ($RecoveryPlan -and $ProtectionGroup) {
foreach ($pg in $ProtectionGroup) {
try {
$RecoveryPlan.AddProtectionGroup($pg.MoRef)
} catch {
Write-Error $_
}
}
}
}
<#
.SYNOPSIS
Remove a protection group to a recovery plan. This requires SRM 6.5 or later.
.PARAMETER RecoveryPlan
The recovery plan the protection group will be disassociated from
.PARAMETER ProtectionGroup
The protection group to disassociate from the recovery plan
#>
Function Remove-ProtectionGroupFromRecoveryPlan {
[cmdletbinding()]
Param(
[Parameter (Mandatory=$true)][VMware.VimAutomation.Srm.Views.SrmRecoveryPlan] $RecoveryPlan,
[Parameter (Mandatory=$true)][VMware.VimAutomation.Srm.Views.SrmProtectionGroup] $ProtectionGroup
)
if ($RecoveryPlan -and $ProtectionGroup) {
foreach ($pg in $ProtectionGroup) {
try {
$RecoveryPlan.RemoveProtectionGroupFromRecoveryPlan($pg.MoRef)
} catch {
Write-Error $_
}
}
}
}
<#
.SYNOPSIS
Get the recovery settings of a protected VM. This requires SRM 5.8 or later.
.PARAMETER RecoveryPlan
The recovery plan the settings will be retrieved from.
.PARAMETER Vm
The virtual machine to retieve recovery settings for.
#>
Function Get-RecoverySetting {
[cmdletbinding()]
Param(
[Parameter (Mandatory=$true)][VMware.VimAutomation.Srm.Views.SrmRecoveryPlan] $RecoveryPlan,
[Parameter (ValueFromPipeline=$true)][VMware.VimAutomation.ViCore.Types.V1.Inventory.VirtualMachine] $Vm,
[Parameter (ValueFromPipeline=$true)][VMware.Vim.VirtualMachine] $VmView,
[Parameter (ValueFromPipeline=$true)][VMware.VimAutomation.Srm.Views.SrmProtectionGroupProtectedVm] $ProtectedVm
)
$moRef = Get_MoRefFromVmObj -Vm $Vm -VmView $VmView -ProtectedVm $ProtectedVm
if ($RecoveryPlan -and $moRef) {
$RecoveryPlan.GetRecoverySettings($moRef)
}
}
<#
.SYNOPSIS
Get the recovery settings of a protected VM. This requires SRM 5.8 or later.
.PARAMETER RecoveryPlan
The recovery plan the settings will be retrieved from.
.PARAMETER Vm
The virtual machine to configure recovery settings on.
.PARAMETER RecoverySettings
The recovery settings to configure. These should have been retrieved via a
call to Get-RecoverySettings
#>
Function Set-RecoverySetting {
[cmdletbinding(SupportsShouldProcess=$true, ConfirmImpact="Medium")]
Param(
[Parameter (Mandatory=$true)][VMware.VimAutomation.Srm.Views.SrmRecoveryPlan] $RecoveryPlan,
[Parameter (ValueFromPipeline=$true)][VMware.VimAutomation.ViCore.Types.V1.Inventory.VirtualMachine] $Vm,
[Parameter (ValueFromPipeline=$true)][VMware.Vim.VirtualMachine] $VmView,
[Parameter (ValueFromPipeline=$true)][VMware.VimAutomation.Srm.Views.SrmProtectionGroupProtectedVm] $ProtectedVm,
[Parameter (Mandatory=$true, ValueFromPipeline=$true)][VMware.VimAutomation.Srm.Views.SrmRecoverySettings] $RecoverySettings
)
$moRef = Get_MoRefFromVmObj -Vm $Vm -VmView $VmView -ProtectedVm $ProtectedVm
if ($RecoveryPlan -and $moRef -and $RecoverySettings) {
if ($PSCmdlet.ShouldProcess("$moRef", "Set")) {
$RecoveryPlan.SetRecoverySettings($moRef, $RecoverySettings)
}
}
}
<#
.SYNOPSIS
Create a new per-Vm command to add to the SRM Recovery Plan
.PARAMETER Command
The command script to execute.
.PARAMETER Description
The user friendly description of this script.
.PARAMETER Timeout
The number of seconds this command has to execute before it will be timedout.
.PARAMETER RunInRecoveredVm
For a post-power on command this flag determines whether it will run on the
recovered VM or on the SRM server.
#>
Function New-Command {
[cmdletbinding(SupportsShouldProcess=$true, ConfirmImpact="None")]
Param(
[Parameter (Mandatory=$true)][string] $Command,
[Parameter (Mandatory=$true)][string] $Description,
[int] $Timeout = 300,
[switch] $RunInRecoveredVm = $false
)
if($PSCmdlet.ShouldProcess("Description", "New")) {
$srmWsdlCmd = New-Object VMware.VimAutomation.Srm.WsdlTypes.SrmCommand
$srmCmd = New-Object VMware.VimAutomation.Srm.Views.SrmCommand -ArgumentList $srmWsdlCmd
$srmCmd.Command = $Command
$srmCmd.Description = $Description
$srmCmd.RunInRecoveredVm = $RunInRecoveredVm
$srmCmd.Timeout = $Timeout
$srmCmd.Uuid = [guid]::NewGuid()
return $srmCmd
}
}
<# Internal function #>
Function Add_Command {
[cmdletbinding()]
Param(
[Parameter (Mandatory=$true, ValueFromPipeline=$true)][VMware.VimAutomation.Srm.Views.SrmRecoverySettings] $RecoverySettings,
[Parameter (Mandatory=$true)][VMware.VimAutomation.Srm.Views.SrmCommand] $SrmCommand,
[Parameter (Mandatory=$true)][bool] $PostRecovery
)
if ($PostRecovery) {
$commands = $RecoverySettings.PostPowerOnCallouts
} else {
$commands = $RecoverySettings.PrePowerOnCallouts
}
if (-not $commands) {
$commands = New-Object System.Collections.Generic.List[VMware.VimAutomation.Srm.Views.SrmCallout]
}
$commands.Add($SrmCommand)
if ($PostRecovery) {
$RecoverySettings.PostPowerOnCallouts = $commands
} else {
$RecoverySettings.PrePowerOnCallouts = $commands
}
}
<#
.SYNOPSIS
Add an SRM command to the set of pre recovery callouts for a VM.
.PARAMETER RecoverySettings
The recovery settings to update. These should have been retrieved via a
call to Get-RecoverySettings
.PARAMETER SrmCommand
The command to add to the list.
#>
Function Add-PreRecoveryCommand {
[cmdletbinding()]
[OutputType([VMware.VimAutomation.Srm.Views.SrmRecoverySettings])]
Param(
[Parameter (Mandatory=$true, ValueFromPipeline=$true)][VMware.VimAutomation.Srm.Views.SrmRecoverySettings] $RecoverySettings,
[Parameter (Mandatory=$true)][VMware.VimAutomation.Srm.Views.SrmCommand] $SrmCommand
)
Add_Command -RecoverySettings $RecoverySettings -SrmCommand $SrmCommand -PostRecovery $false
return $RecoverySettings
}
<#
.SYNOPSIS
Remove an SRM command from the set of pre recovery callouts for a VM.
.PARAMETER RecoverySettings
The recovery settings to update. These should have been retrieved via a
call to Get-RecoverySettings
.PARAMETER SrmCommand
The command to remove from the list.
#>
Function Remove-PreRecoveryCommand {
[cmdletbinding(SupportsShouldProcess=$true, ConfirmImpact="Low")]
[OutputType([VMware.VimAutomation.Srm.Views.SrmRecoverySettings])]
Param(
[Parameter (Mandatory=$true, ValueFromPipeline=$true)][VMware.VimAutomation.Srm.Views.SrmRecoverySettings] $RecoverySettings,
[Parameter (Mandatory=$true)][VMware.VimAutomation.Srm.Views.SrmCommand] $SrmCommand
)
if ($pscmdlet.ShouldProcess($SrmCommand.Description, "Remove")) {
$RecoverySettings.PrePowerOnCallouts.Remove($SrmCommand)
}
return $RecoverySettings
}
<#
.SYNOPSIS
Add an SRM command to the set of post recovery callouts for a VM.
.PARAMETER RecoverySettings
The recovery settings to update. These should have been retrieved via a
call to Get-RecoverySettings
.PARAMETER SrmCommand
The command to add to the list.
#>
Function Add-PostRecoveryCommand {
[cmdletbinding()]
[OutputType([VMware.VimAutomation.Srm.Views.SrmRecoverySettings])]
Param(
[Parameter (Mandatory=$true, ValueFromPipeline=$true)][VMware.VimAutomation.Srm.Views.SrmRecoverySettings] $RecoverySettings,
[Parameter (Mandatory=$true)][VMware.VimAutomation.Srm.Views.SrmCommand] $SrmCommand
)
Add_Command -RecoverySettings $RecoverySettings -SrmCommand $SrmCommand -PostRecovery $true
return $RecoverySettings
}
<#
.SYNOPSIS
Remove an SRM command from the set of post recovery callouts for a VM.
.PARAMETER RecoverySettings
The recovery settings to update. These should have been retrieved via a
call to Get-RecoverySettings
.PARAMETER SrmCommand
The command to remove from the list.
#>
Function Remove-PostRecoveryCommand {
[cmdletbinding(SupportsShouldProcess=$true, ConfirmImpact="Low")]
[OutputType([VMware.VimAutomation.Srm.Views.SrmRecoverySettings])]
Param(
[Parameter (Mandatory=$true, ValueFromPipeline=$true)][VMware.VimAutomation.Srm.Views.SrmRecoverySettings] $RecoverySettings,
[Parameter (Mandatory=$true)][VMware.VimAutomation.Srm.Views.SrmCommand] $SrmCommand
)
if ($pscmdlet.ShouldProcess($SrmCommand.Description, "Remove")) {
$RecoverySettings.PostPowerOnCallouts.Remove($SrmCommand)
}
return $RecoverySettings
}
<#
.SYNOPSIS
Create a new recovery plan
.PARAMETER Name
The name for this recovery plan
.PARAMETER Description
A description of the recovery plan
.PARAMETER Folder
The recovery plan folder in which to create this recovery plan. Will default to
the root recovery plan folder
.PARAMETER ProtectionGroups
The protection groups to associate with this recovery plan
.PARAMETER TestNetworkMappings
The test network mappings to configure as part of this recovery plan
.PARAMETER SrmServer
The SRM Server to operate against
#>
Function New-RecoveryPlan {
[cmdletbinding(SupportsShouldProcess=$true, ConfirmImpact="Medium")]
Param(
[Parameter (Mandatory=$true)][string] $Name,
[string] $Description,
[VMware.VimAutomation.Srm.Views.SrmRecoveryPlanFolder] $Folder,
[VMware.VimAutomation.Srm.Views.SrmProtectionGroup[]] $ProtectionGroups,
[VMware.VimAutomation.Srm.Views.SrmRecoveryTestNetworkMapping[]] $TestNetworkMappings,
[VMware.VimAutomation.Srm.Types.V1.SrmServer] $SrmServer
)
$api = Get-ServerApiEndpoint -SrmServer $SrmServer
if (-not $Folder) {
$Folder = Get-RecoveryPlanFolder -SrmServer $SrmServer
}
$protectionGroupmRefs += @( $ProtectionGroups | ForEach-Object { $_.MoRef } | Select-Object -Unique)
[VMware.VimAutomation.Srm.Views.CreateRecoveryPlanTask] $task = $null
if ($PSCmdlet.ShouldProcess($Name, "New")) {
$task = $api.Recovery.CreateRecoveryPlan(
$Name,
$Folder.MoRef,
$protectionGroupmRefs,
$Description,
$TestNetworkMappings
)
}
while(-not $task.IsCreateRecoveryPlanComplete()) { Start-Sleep -Seconds 1 }
$task.GetNewRecoveryPlan()
}
<#
.SYNOPSIS
Remove a recovery plan permanently
.PARAMETER RecoveryPlan
The recovery plan to remove
.PARAMETER SrmServer
The SRM Server to operate against
#>
Function Remove-RecoveryPlan {
[cmdletbinding(SupportsShouldProcess=$True, ConfirmImpact="High")]
Param(
[Parameter (Mandatory=$true)][VMware.VimAutomation.Srm.Views.SrmRecoveryPlan] $RecoveryPlan,
[VMware.VimAutomation.Srm.Types.V1.SrmServer] $SrmServer
)
$api = Get-ServerApiEndpoint -SrmServer $SrmServer
$rpinfo = $RecoveryPlan.GetInfo()
if ($pscmdlet.ShouldProcess($rpinfo.Name, "Remove")) {
$api.Recovery.DeleteRecoveryPlan($RecoveryPlan.MoRef)
}
}
<#
.SYNOPSIS
Get a recovery plan folder
.PARAMETER SrmServer
The SRM Server to query for the recovery plan folder
#>
Function Get-RecoveryPlanFolder {
[cmdletbinding()]
Param(
[VMware.VimAutomation.Srm.Types.V1.SrmServer] $SrmServer
)
$api = Get-ServerApiEndpoint -SrmServer $SrmServer
$folder = $api.Recovery.GetRecoveryPlanRootFolder()
return $folder
}

View File

@@ -0,0 +1,24 @@
# SRM Helper Methods - https://github.com/benmeadowcroft/SRM-Cmdlets
<#
.SYNOPSIS
Trigger Discover Devices for Site Recovery Manager
.OUTPUTS
Returns discover devices task
#>
Function Start-DiscoverDevice {
[cmdletbinding(SupportsShouldProcess=$True, ConfirmImpact="Medium")]
[OutputType([VMware.VimAutomation.Srm.Views.DiscoverDevicesTask])]
Param(
[VMware.VimAutomation.Srm.Types.V1.SrmServer] $SrmServer
)
$api = Get-ServerApiEndpoint -SrmServer $SrmServer
$name = $SrmServer.Name
[VMware.VimAutomation.Srm.Views.DiscoverDevicesTask] $task = $null
if ($pscmdlet.ShouldProcess($name, "Rescan Storage Devices")) {
$task = $api.Storage.DiscoverDevices()
}
return $task
}

View File

@@ -0,0 +1,92 @@
#
# Module manifest for module 'Meadowcroft.Srm'
#
@{
# Script module or binary module file associated with this manifest.
RootModule = 'Meadowcroft.Srm.psm1'
# Version number of this module.
ModuleVersion = '0.2'
# ID used to uniquely identify this module
GUID = 'f9247009-9168-4a21-831b-819f82884ffe'
# Author of this module
Author = 'Ben Meadowcroft'
# Company or vendor of this module
CompanyName = 'VMware, Inc'
# Copyright statement for this module
Copyright = '(c) 2014 - 2017. All rights reserved.'
# Description of the functionality provided by this module
# Description = ''
# Minimum version of the Windows PowerShell engine required by this module
# PowerShellVersion = ''
# Name of the Windows PowerShell host required by this module
# PowerShellHostName = ''
# Minimum version of the Windows PowerShell host required by this module
# PowerShellHostVersion = ''
# Minimum version of Microsoft .NET Framework required by this module
# DotNetFrameworkVersion = ''
# Minimum version of the common language runtime (CLR) required by this module
# CLRVersion = ''
# Processor architecture (None, X86, Amd64) required by this module
# ProcessorArchitecture = ''
# Modules that must be imported into the global environment prior to importing this module
RequiredModules = @{ModuleName='VMware.VimAutomation.Srm'; ModuleVersion='6.5'}
# Assemblies that must be loaded prior to importing this module
# RequiredAssemblies = @()
# Script files (.ps1) that are run in the caller's environment prior to importing this module.
# ScriptsToProcess = @()
# Type files (.ps1xml) to be loaded when importing this module
# TypesToProcess = @()
# Format files (.ps1xml) to be loaded when importing this module
# FormatsToProcess = @()
# Modules to import as nested modules of the module specified in RootModule/ModuleToProcess
NestedModules = 'Meadowcroft.Srm.Recovery.ps1','Meadowcroft.Srm.Protection.ps1','Meadowcroft.Srm.Storage.ps1'
# NestedModules = @()
# Functions to export from this module, note that internal functions use '_' not '-' as separator
FunctionsToExport = '*-*'
# Cmdlets to export from this module
CmdletsToExport = '*'
# Variables to export from this module
VariablesToExport = '*'
# Aliases to export from this module
AliasesToExport = '*'
# List of all modules packaged with this module
# ModuleList = @()
# List of all files packaged with this module
# FileList = @()
# Private data to pass to the module specified in RootModule/ModuleToProcess
# PrivateData = ''
# HelpInfo URI of this module
# HelpInfoURI = ''
# Default prefix for commands exported from this module. Override the default prefix using Import-Module -Prefix.
DefaultCommandPrefix = 'Srm'
}

View File

@@ -0,0 +1,148 @@
# SRM Helper Methods - https://github.com/benmeadowcroft/SRM-Cmdlets
<#
.SYNOPSIS
This is intended to be an "internal" function only. It filters a
pipelined input of objects and elimiates duplicates as identified
by the MoRef property on the object.
.LINK
https://github.com/benmeadowcroft/SRM-Cmdlets/
#>
Function Select_UniqueByMoRef {
Param(
[Parameter (ValueFromPipeline=$true)] $in
)
process {
$moref = New-Object System.Collections.ArrayList
$in | Sort-Object | Select-Object MoRef -Unique | ForEach-Object { $moref.Add($_.MoRef) } > $null
$in | ForEach-Object {
if ($_.MoRef -in $moref) {
$moref.Remove($_.MoRef)
$_ #output
}
}
}
}
<#
.SYNOPSIS
This is intended to be an "internal" function only. It gets the
MoRef property of a VM from either a VM object, a VM view, or the
protected VM object.
#>
Function Get_MoRefFromVmObj {
Param(
[Parameter (ValueFromPipeline=$true)][VMware.VimAutomation.ViCore.Types.V1.Inventory.VirtualMachine] $Vm,
[Parameter (ValueFromPipeline=$true)][VMware.Vim.VirtualMachine] $VmView,
[Parameter (ValueFromPipeline=$true)][VMware.VimAutomation.Srm.Views.SrmProtectionGroupProtectedVm] $ProtectedVm
)
$moRef = $null
if ($Vm.ExtensionData.MoRef) { # VM object
$moRef = $Vm.ExtensionData.MoRef
} elseif ($VmView.MoRef) { # VM view
$moRef = $VmView.MoRef
} elseif ($protectedVm) {
$moRef = $ProtectedVm.Vm.MoRef
}
$moRef
}
<#
.SYNOPSIS
Lookup the srm instance for a specific server.
#>
Function Get-Server {
[cmdletbinding()]
Param(
[string] $SrmServerAddress,
[VMware.VimAutomation.Srm.Types.V1.SrmServer] $SrmServer
)
$found = $null
if ($SrmServer) {
$found = $SrmServer
} elseif ($SrmServerAddress) {
# search for server address in default servers
$global:DefaultSrmServers | ForEach-Object {
if ($_.Name -ieq $SrmServerAddress) {
$found = $_
}
}
if (-not $found) {
throw "SRM server $SrmServerAddress not found. Connect-Server must be called first."
}
}
if (-not $found) {
#default result
$found = $global:DefaultSrmServers[0]
}
return $found;
}
<#
.SYNOPSIS
Retrieve the SRM Server Version
#>
Function Get-ServerVersion {
[cmdletbinding()]
Param(
[VMware.VimAutomation.Srm.Types.V1.SrmServer] $SrmServer
)
$srm = Get-Server $SrmServer
$srm.Version
}
<#
.SYNOPSIS
Lookup the SRM API endpoint for a specific server.
#>
Function Get-ServerApiEndpoint {
[cmdletbinding()]
Param(
[string] $SrmServerAddress,
[VMware.VimAutomation.Srm.Types.V1.SrmServer] $SrmServer
)
[VMware.VimAutomation.Srm.Types.V1.SrmServer] $server = Get-Server -SrmServerAddress $SrmServerAddress -SrmServer $SrmServer
return $server.ExtensionData
}
<#
.SYNOPSIS
Get the placeholder VMs that are associated with SRM
#>
Function Get-PlaceholderVM {
[cmdletbinding()]
Param()
Get-VM @Args | Where-Object {$_.ExtensionData.Config.ManagedBy.extensionKey -like "com.vmware.vcDr*" -and $_.ExtensionData.Config.ManagedBy.Type -ieq 'placeholderVm'}
}
<#
.SYNOPSIS
Get the test VMs that are associated with SRM
#>
Function Get-TestVM {
[cmdletbinding()]
Param()
Get-VM @Args | Where-Object {$_.ExtensionData.Config.ManagedBy.extensionKey -like "com.vmware.vcDr*" -and $_.ExtensionData.Config.ManagedBy.Type -ieq 'testVm'}
}
<#
.SYNOPSIS
Get the VMs that are replicated using vSphere Replication. These may not be SRM
protected VMs.
#>
Function Get-ReplicatedVM {
[cmdletbinding()]
Param()
Get-VM @Args | Where-Object {($_.ExtensionData.Config.ExtraConfig | Where-Object { $_.Key -eq 'hbr_filter.destination' -and $_.Value } )}
}

7
Modules/SRM/NOTICE.txt Normal file
View File

@@ -0,0 +1,7 @@
Copyright (c) 2017 VMware, Inc. All Rights Reserved.
This product is licensed to you under the Apache License version 2.0 (the "License"). You may not use this product except in compliance with the License.
This product may include a number of subcomponents with separate copyright notices and license terms. Your use of these subcomponents is subject to the terms and conditions of the subcomponent's license, as noted in the LICENSE file.

81
Modules/SRM/README.md Normal file
View File

@@ -0,0 +1,81 @@
# SRM PowerCLI Cmdlets
Helper functions for working with VMware SRM 6.5 with PowerCLI 6.5.1 or later. PowerShell 5.0 and above is required.
This module is provided for illustrative/educational purposes to explain how the PowerCLI access to the SRM public API can be used.
## Getting Started
### Getting the SRM cmdlets
The latest version of the software can be cloned from the git repository:
git clone https://github.com/benmeadowcroft/SRM-Cmdlets.git
Or downloaded as a [zip file](https://github.com/benmeadowcroft/SRM-Cmdlets/archive/master.zip).
Specific releases (compatible with earlier PowerCLI and SRM versions) can be downloaded via the [release page](https://github.com/benmeadowcroft/SRM-Cmdlets/releases).
### Deploy SRM-Cmdlets module
After cloning (or downloading and extracting) the PowerShell module, you can import the module into your current PowerShell session by by passing the path to `Meadowcroft.Srm.psd1` to the `Import-Module` cmdlet, e.g.:
Import-Module -Name .\SRM-Cmdlets\Meadowcroft.Srm.psd1
You can also install the module into the PowerShell path so it can be loaded implicitly. See [Microsoft's Installing Modules instructions](http://msdn.microsoft.com/en-us/library/dd878350) for more details on how to do this.
The module uses the default prefix of `Srm` for the custom functions it defines. This can be overridden when importing the module by setting the value of the `-Prefix` parameter when calling `Import-Module`.
### Connecting to SRM
After installing the module the next step is to connect to the SRM server. Details of how to do this are located in the [PowerCLI 6.5.1 User's Guide](http://pubs.vmware.com/vsphere-65/topic/com.vmware.powercli.ug.doc/GUID-A5F206CF-264D-4565-8CB9-4ED1C337053F.html)
$credential = Get-Credential
Connect-VIServer -Server vc-a.example.com -Credential $credential
Connect-SrmServer -Credential $credential -RemoteCredential $credential
At this point we've just been using the cmdlets provided by PowerCLI, the PowerCLI documentation also provides some examples of how to call the SRM API to perform various tasks. In the rest of this introduction we'll perform some of those tasks using the custom functions defined in this project.
### Report the Protected Virtual Machines and Their Protection Groups
Goal: Create a simple report listing the VMs protected by SRM and the protection group they belong to.
Get-SrmProtectionGroup | %{
$pg = $_
Get-SrmProtectedVM -ProtectionGroup $pg } | %{
$output = "" | select VmName, PgName
$output.VmName = $_.Vm.Name
$output.PgName = $pg.GetInfo().Name
$output
} | Format-Table @{Label="VM Name"; Expression={$_.VmName} },
@{Label="Protection group name"; Expression={$_.PgName}
}
### Report the Last Recovery Plan Test
Goal: Create a simple report listing the state of the last test of a recovery plan
Get-SrmRecoveryPlan | %{ $_ |
Get-SrmRecoveryPlanResult -RecoveryMode Test | select -First 1
} | Select Name, StartTime, RunMode, ResultState | Format-Table
### Execute a Recovery Plan Test
Goal: for a specific recovery plan, execute a test failover. Note the "local" SRM server we are connected to should be the recovery site in order for this to be successful.
Get-SrmRecoveryPlan -Name "Name of Plan" | Start-SrmRecoveryPlan -RecoveryMode Test
### Export the Detailed XML Report of the Last Recovery Plan Workflow
Goal: get the XML report of the last recovery plan execution for a specific recovery plan.
Get-SrmRecoveryPlan -Name "Name of Plan" | Get-SrmRecoveryPlanResult |
select -First 1 | Export-SrmRecoveryPlanResultAsXml
### Protect a Replicated VM
Goal: Take a VM replicated using vSphere Replication or Array Based Replication, add it to an appropriate protection group and configure it for protection
$pg = Get-SrmProtectionGroup "Name of Protection Group"
Get-VM vm-01a | Protect-SrmVM -ProtectionGroup $pg

716
Modules/VAMI/VAMI.psm1 Executable file
View File

@@ -0,0 +1,716 @@
Function Get-VAMISummary {
<#
.NOTES
===========================================================================
Created by: William Lam
Organization: VMware
Blog: www.virtuallyghetto.com
Twitter: @lamw
===========================================================================
.SYNOPSIS
This function retrieves some basic information from VAMI interface (5480)
for a VCSA node which can be an Embedded VCSA, External PSC or External VCSA.
.DESCRIPTION
Function to return basic VAMI summary info
.EXAMPLE
Connect-CisServer -Server 192.168.1.51 -User administrator@vsphere.local -Password VMware1!
Get-VAMISummary
#>
$systemVersionAPI = Get-CisService -Name 'com.vmware.appliance.system.version'
$results = $systemVersionAPI.get() | select product, type, version, build, install_time
$systemUptimeAPI = Get-CisService -Name 'com.vmware.appliance.system.uptime'
$ts = [timespan]::fromseconds($systemUptimeAPI.get().toString())
$uptime = $ts.ToString("hh\:mm\:ss\,fff")
$summaryResult = [pscustomobject] @{
Product = $results.product;
Type = $results.type;
Version = $results.version;
Build = $results.build;
InstallTime = $results.install_time;
Uptime = $uptime
}
$summaryResult
}
Function Get-VAMIHealth {
<#
.NOTES
===========================================================================
Created by: William Lam
Organization: VMware
Blog: www.virtuallyghetto.com
Twitter: @lamw
===========================================================================
.SYNOPSIS
This function retrieves health information from VAMI interface (5480)
for a VCSA node which can be an Embedded VCSA, External PSC or External VCSA.
.DESCRIPTION
Function to return VAMI health
.EXAMPLE
Connect-CisServer -Server 192.168.1.51 -User administrator@vsphere.local -Password VMware1!
Get-VAMIHealth
#>
$healthOverall = (Get-CisService -Name 'com.vmware.appliance.health.system').get()
$healthLastCheck = (Get-CisService -Name 'com.vmware.appliance.health.system').lastcheck()
$healthCPU = (Get-CisService -Name 'com.vmware.appliance.health.load').get()
$healthMem = (Get-CisService -Name 'com.vmware.appliance.health.mem').get()
$healthSwap = (Get-CisService -Name 'com.vmware.appliance.health.swap').get()
$healthStorage = (Get-CisService -Name 'com.vmware.appliance.health.storage').get()
# DB health only applicable for Embedded/External VCSA Node
$vami = (Get-CisService -Name 'com.vmware.appliance.system.version').get()
if($vami.type -eq "vCenter Server with an embedded Platform Services Controller" -or $vami.type -eq "vCenter Server with an external Platform Services Controller") {
$healthVCDB = (Get-CisService -Name 'com.vmware.appliance.health.databasestorage').get()
} else {
$healthVCDB = "N/A"
}
$healthSoftwareUpdates = (Get-CisService -Name 'com.vmware.appliance.health.softwarepackages').get()
$healthResult = [pscustomobject] @{
HealthOverall = $healthOverall;
HealthLastCheck = $healthLastCheck;
HealthCPU = $healthCPU;
HealthMem = $healthMem;
HealthSwap = $healthSwap;
HealthStorage = $healthStorage;
HealthVCDB = $healthVCDB;
HealthSoftware = $healthSoftwareUpdates
}
$healthResult
}
Function Get-VAMIAccess {
<#
.NOTES
===========================================================================
Created by: William Lam
Organization: VMware
Blog: www.virtuallyghetto.com
Twitter: @lamw
===========================================================================
.SYNOPSIS
This function retrieves access information from VAMI interface (5480)
for a VCSA node which can be an Embedded VCSA, External PSC or External VCSA.
.DESCRIPTION
Function to return VAMI access interfaces (Console,DCUI,Bash Shell & SSH)
.EXAMPLE
Connect-CisServer -Server 192.168.1.51 -User administrator@vsphere.local -Password VMware1!
Get-VAMIAccess
#>
$consoleAccess = (Get-CisService -Name 'com.vmware.appliance.access.consolecli').get()
$dcuiAccess = (Get-CisService -Name 'com.vmware.appliance.access.dcui').get()
$shellAccess = (Get-CisService -Name 'com.vmware.appliance.access.shell').get()
$sshAccess = (Get-CisService -Name 'com.vmware.appliance.access.ssh').get()
$accessResult = New-Object PSObject -Property @{
Console = $consoleAccess;
DCUI = $dcuiAccess;
BashShell = $shellAccess.enabled;
SSH = $sshAccess
}
$accessResult
}
Function Get-VAMITime {
<#
.NOTES
===========================================================================
Created by: William Lam
Organization: VMware
Blog: www.virtuallyghetto.com
Twitter: @lamw
===========================================================================
.SYNOPSIS
This function retrieves the time and NTP info from VAMI interface (5480)
for a VCSA node which can be an Embedded VCSA, External PSC or External VCSA.
.DESCRIPTION
Function to return current Time and NTP information
.EXAMPLE
Connect-CisServer -Server 192.168.1.51 -User administrator@vsphere.local -Password VMware1!
Get-VAMITime
#>
$systemTimeAPI = Get-CisService -Name 'com.vmware.appliance.system.time'
$timeResults = $systemTimeAPI.get()
$timeSync = (Get-CisService -Name 'com.vmware.appliance.techpreview.timesync').get()
$timeSyncMode = $timeSync.mode
$timeResult = [pscustomobject] @{
Timezone = $timeResults.timezone;
Date = $timeResults.date;
CurrentTime = $timeResults.time;
Mode = $timeSyncMode;
NTPServers = "N/A";
NTPStatus = "N/A";
}
if($timeSyncMode -eq "NTP") {
$ntpServers = (Get-CisService -Name 'com.vmware.appliance.techpreview.ntp').get()
$timeResult.NTPServers = $ntpServers.servers
$timeResult.NTPStatus = $ntpServers.status
}
$timeResult
}
Function Get-VAMINetwork {
<#
.NOTES
===========================================================================
Created by: William Lam
Organization: VMware
Blog: www.virtuallyghetto.com
Twitter: @lamw
===========================================================================
.SYNOPSIS
This function retrieves network information from VAMI interface (5480)
for a VCSA node which can be an Embedded VCSA, External PSC or External VCSA.
.DESCRIPTION
Function to return networking information including details for each interface
.EXAMPLE
Connect-CisServer -Server 192.168.1.51 -User administrator@vsphere.local -Password VMware1!
Get-VAMINetwork
#>
$netResults = @()
$Hostname = (Get-CisService -Name 'com.vmware.appliance.networking.dns.hostname').get()
$dns = (Get-CisService -Name 'com.vmware.appliance.networking.dns.servers').get()
Write-Host "Hostname: " $hostname
Write-Host "DNS Servers: " $dns.servers
$interfaces = (Get-CisService -Name 'com.vmware.appliance.networking.interfaces').list()
foreach ($interface in $interfaces) {
$ipv4API = (Get-CisService -Name 'com.vmware.appliance.techpreview.networking.ipv4')
$spec = $ipv4API.Help.get.interfaces.CreateExample()
$spec+= $interface.name
$ipv4result = $ipv4API.get($spec)
$interfaceResult = [pscustomobject] @{
Inteface = $interface.name;
MAC = $interface.mac;
Status = $interface.status;
Mode = $ipv4result.mode;
IP = $ipv4result.address;
Prefix = $ipv4result.prefix;
Gateway = $ipv4result.default_gateway;
Updateable = $ipv4result.updateable
}
$netResults += $interfaceResult
}
$netResults
}
Function Get-VAMIDisks {
<#
.NOTES
===========================================================================
Created by: William Lam
Organization: VMware
Blog: www.virtuallyghetto.com
Twitter: @lamw
===========================================================================
.SYNOPSIS
This function retrieves VMDK disk number to partition mapping VAMI interface (5480)
for a VCSA node which can be an Embedded VCSA, External PSC or External VCSA.
.DESCRIPTION
Function to return VMDK disk number to OS partition mapping
.EXAMPLE
Connect-CisServer -Server 192.168.1.51 -User administrator@vsphere.local -Password VMware1!
Get-VAMIDisks
#>
$storageAPI = Get-CisService -Name 'com.vmware.appliance.system.storage'
$disks = $storageAPI.list()
foreach ($disk in $disks | sort {[int]$_.disk.toString()}) {
$disk | Select Disk, Partition
}
}
Function Start-VAMIDiskResize {
<#
.NOTES
===========================================================================
Created by: William Lam
Organization: VMware
Blog: www.virtuallyghetto.com
Twitter: @lamw
===========================================================================
.SYNOPSIS
This function triggers an OS partition resize after adding additional disk capacity
for a VCSA node which can be an Embedded VCSA, External PSC or External VCSA.
.DESCRIPTION
Function triggers OS partition resize operation
.EXAMPLE
Connect-CisServer -Server 192.168.1.51 -User administrator@vsphere.local -Password VMware1!
Start-VAMIDiskResize
#>
$storageAPI = Get-CisService -Name 'com.vmware.appliance.system.storage'
Write-Host "Initiated OS partition resize operation ..."
$storageAPI.resize()
}
Function Get-VAMIStatsList {
<#
.NOTES
===========================================================================
Created by: William Lam
Organization: VMware
Blog: www.virtuallyghetto.com
Twitter: @lamw
===========================================================================
.SYNOPSIS
This function retrieves list avialable monitoring metrics in VAMI interface (5480)
for a VCSA node which can be an Embedded VCSA, External PSC or External VCSA.
.DESCRIPTION
Function to return list of available monitoring metrics that can be queried
.EXAMPLE
Connect-CisServer -Server 192.168.1.51 -User administrator@vsphere.local -Password VMware1!
Get-VAMIStatsList
#>
$monitoringAPI = Get-CisService -Name 'com.vmware.appliance.monitoring'
$ids = $monitoringAPI.list() | Select id | Sort-Object -Property id
foreach ($id in $ids) {
$id
}
}
Function Get-VAMIStorageUsed {
<#
.NOTES
===========================================================================
Created by: William Lam
Organization: VMware
Blog: www.virtuallyghetto.com
Twitter: @lamw
===========================================================================
.SYNOPSIS
This function retrieves the individaul OS partition storage utilization
for a VCSA node which can be an Embedded VCSA, External PSC or External VCSA.
.DESCRIPTION
Function to return individual OS partition storage utilization
.EXAMPLE
Connect-CisServer -Server 192.168.1.51 -User administrator@vsphere.local -Password VMware1!
Get-VAMIStorageUsed
#>
$monitoringAPI = Get-CisService 'com.vmware.appliance.monitoring'
$querySpec = $monitoringAPI.help.query.item.CreateExample()
# List of IDs from Get-VAMIStatsList to query
$querySpec.Names = @(
"storage.used.filesystem.autodeploy",
"storage.used.filesystem.boot",
"storage.used.filesystem.coredump",
"storage.used.filesystem.imagebuilder",
"storage.used.filesystem.invsvc",
"storage.used.filesystem.log",
"storage.used.filesystem.netdump",
"storage.used.filesystem.root",
"storage.used.filesystem.updatemgr",
"storage.used.filesystem.vcdb_core_inventory",
"storage.used.filesystem.vcdb_seat",
"storage.used.filesystem.vcdb_transaction_log",
"storage.totalsize.filesystem.autodeploy",
"storage.totalsize.filesystem.boot",
"storage.totalsize.filesystem.coredump",
"storage.totalsize.filesystem.imagebuilder",
"storage.totalsize.filesystem.invsvc",
"storage.totalsize.filesystem.log",
"storage.totalsize.filesystem.netdump",
"storage.totalsize.filesystem.root",
"storage.totalsize.filesystem.updatemgr",
"storage.totalsize.filesystem.vcdb_core_inventory",
"storage.totalsize.filesystem.vcdb_seat",
"storage.totalsize.filesystem.vcdb_transaction_log"
)
# Tuple (Filesystem Name, Used, Total) to store results
$storageStats = @{
"autodeploy"=@{"name"="/storage/autodeploy";"used"=0;"total"=0};
"boot"=@{"name"="/boot";"used"=0;"total"=0};
"coredump"=@{"name"="/storage/core";"used"=0;"total"=0};
"imagebuilder"=@{"name"="/storage/imagebuilder";"used"=0;"total"=0};
"invsvc"=@{"name"="/storage/invsvc";"used"=0;"total"=0};
"log"=@{"name"="/storage/log";"used"=0;"total"=0};
"netdump"=@{"name"="/storage/netdump";"used"=0;"total"=0};
"root"=@{"name"="/";"used"=0;"total"=0};
"updatemgr"=@{"name"="/storage/updatemgr";"used"=0;"total"=0};
"vcdb_core_inventory"=@{"name"="/storage/db";"used"=0;"total"=0};
"vcdb_seat"=@{"name"="/storage/seat";"used"=0;"total"=0};
"vcdb_transaction_log"=@{"name"="/storage/dblog";"used"=0;"total"=0}
}
$querySpec.interval = "DAY1"
$querySpec.function = "MAX"
$querySpec.start_time = ((get-date).AddDays(-1))
$querySpec.end_time = (Get-Date)
$queryResults = $monitoringAPI.query($querySpec) | Select * -ExcludeProperty Help
foreach ($queryResult in $queryResults) {
# Update hash if its used storage results
if($queryResult.name -match "used") {
$key = (($queryResult.name).toString()).split(".")[-1]
$value = [Math]::Round([int]($queryResult.data[1]).toString()/1MB,2)
$storageStats[$key]["used"] = $value
# Update hash if its total storage results
} else {
$key = (($queryResult.name).toString()).split(".")[-1]
$value = [Math]::Round([int]($queryResult.data[1]).toString()/1MB,2)
$storageStats[$key]["total"] = $value
}
}
$storageResults = @()
foreach ($key in $storageStats.keys | Sort-Object -Property name) {
$statResult = [pscustomobject] @{
Filesystem = $storageStats[$key].name;
Used = $storageStats[$key].used;
Total = $storageStats[$key].total
}
$storageResults += $statResult
}
$storageResults
}
Function Get-VAMIService {
<#
.NOTES
===========================================================================
Created by: William Lam
Organization: VMware
Blog: www.virtuallyghetto.com
Twitter: @lamw
===========================================================================
.SYNOPSIS
This function retrieves list of services in VAMI interface (5480)
for a VCSA node which can be an Embedded VCSA, External PSC or External VCSA.
.DESCRIPTION
Function to return list of services and their description
.EXAMPLE
Connect-CisServer -Server 192.168.1.51 -User administrator@vsphere.local -Password VMware1!
Get-VAMIService
.EXAMPLE
Get-VAMIService -Name rbd
#>
param(
[Parameter(
Mandatory=$false,
ValueFromPipeline=$true,
ValueFromPipelineByPropertyName=$true)
]
[String]$Name
)
if($Name -ne "") {
$vMonAPI = Get-CisService 'com.vmware.appliance.vmon.service'
try {
$serviceStatus = $vMonAPI.get($name,0)
$serviceString = [pscustomobject] @{
Name = $name;
State = $serviceStatus.state;
Health = "";
Startup = $serviceStatus.startup_type
}
if($serviceStatus.health -eq $null) { $serviceString.Health = "N/A"} else { $serviceString.Health = $serviceStatus.health }
$serviceString
} catch {
Write-Error $Error[0].exception.Message
}
} else {
$vMonAPI = Get-CisService 'com.vmware.appliance.vmon.service'
$services = $vMonAPI.list_details()
$serviceResult = @()
foreach ($key in $services.keys | Sort-Object -Property Value) {
$serviceString = [pscustomobject] @{
Name = $key;
State = $services[$key].state;
Health = "N/A";
Startup = $services[$key].Startup_type
}
if($services[$key].health -eq $null) { $serviceString.Health = "N/A"} else { $serviceString.Health = $services[$key].health }
$serviceResult += $serviceString
}
$serviceResult
}
}
Function Start-VAMIService {
<#
.NOTES
===========================================================================
Created by: William Lam
Organization: VMware
Blog: www.virtuallyghetto.com
Twitter: @lamw
===========================================================================
.SYNOPSIS
This function retrieves list of services in VAMI interface (5480)
for a VCSA node which can be an Embedded VCSA, External PSC or External VCSA.
.DESCRIPTION
Function to return list of services and their description
.EXAMPLE
Connect-CisServer -Server 192.168.1.51 -User administrator@vsphere.local -Password VMware1!
Start-VAMIService -Name rbd
#>
param(
[Parameter(
Mandatory=$true,
ValueFromPipeline=$true,
ValueFromPipelineByPropertyName=$true)
]
[String]$Name
)
$vMonAPI = Get-CisService 'com.vmware.appliance.vmon.service'
try {
Write-Host "Starting $name service ..."
$vMonAPI.start($name)
} catch {
Write-Error $Error[0].exception.Message
}
}
Function Stop-VAMIService {
<#
.NOTES
===========================================================================
Created by: William Lam
Organization: VMware
Blog: www.virtuallyghetto.com
Twitter: @lamw
===========================================================================
.SYNOPSIS
This function retrieves list of services in VAMI interface (5480)
for a VCSA node which can be an Embedded VCSA, External PSC or External VCSA.
.DESCRIPTION
Function to return list of services and their description
.EXAMPLE
Connect-CisServer -Server 192.168.1.51 -User administrator@vsphere.local -Password VMware1!
Stop-VAMIService -Name rbd
#>
param(
[Parameter(
Mandatory=$true,
ValueFromPipeline=$true,
ValueFromPipelineByPropertyName=$true)
]
[String]$Name
)
$vMonAPI = Get-CisService 'com.vmware.appliance.vmon.service'
try {
Write-Host "Stopping $name service ..."
$vMonAPI.stop($name)
} catch {
Write-Error $Error[0].exception.Message
}
}
Function Get-VAMIBackupSize {
<#
.NOTES
===========================================================================
Created by: William Lam
Organization: VMware
Blog: www.virtuallyghetto.com
Twitter: @lamw
===========================================================================
.SYNOPSIS
This function retrieves the backup size of the VCSA from VAMI interface (5480)
for a VCSA node which can be an Embedded VCSA, External PSC or External VCSA.
.DESCRIPTION
Function to return the current backup size of the VCSA (common and core data)
.EXAMPLE
Connect-CisServer -Server 192.168.1.51 -User administrator@vsphere.local -Password VMware1!
Get-VAMIBackupSize
#>
$recoveryAPI = Get-CisService 'com.vmware.appliance.recovery.backup.parts'
$backupParts = $recoveryAPI.list() | select id
$estimateBackupSize = 0
$backupPartSizes = ""
foreach ($backupPart in $backupParts) {
$partId = $backupPart.id.value
$partSize = $recoveryAPI.get($partId)
$estimateBackupSize += $partSize
$backupPartSizes += $partId + " data is " + $partSize + " MB`n"
}
Write-Host "Estimated Backup Size: $estimateBackupSize MB"
Write-Host $backupPartSizes
}
Function Get-VAMIUser {
<#
.NOTES
===========================================================================
Created by: William Lam
Organization: VMware
Blog: www.virtuallyghetto.com
Twitter: @lamw
===========================================================================
.SYNOPSIS
This function retrieves VAMI local users using VAMI interface (5480)
for a VCSA node which can be an Embedded VCSA, External PSC or External VCSA.
.DESCRIPTION
Function to retrieve VAMI local users
.EXAMPLE
Connect-CisServer -Server 192.168.1.51 -User administrator@vsphere.local -Password VMware1!
Get-VAMIUser
#>
param(
[Parameter(
Mandatory=$false,
ValueFromPipeline=$true,
ValueFromPipelineByPropertyName=$true)
]
[String]$Name
)
$userAPI = Get-CisService 'com.vmware.appliance.techpreview.localaccounts.user'
$userResults = @()
if($Name -ne "") {
try {
$user = $userAPI.get($name)
$userString = [pscustomobject] @{
User = $user.username
Name = $user.fullname
Email = $user.email
Status = $user.status
PasswordStatus = $user.passwordstatus
Role = $user.role
}
$userResults += $userString
} catch {
Write-Error $Error[0].exception.Message
}
} else {
$users = $userAPI.list()
foreach ($user in $users) {
$userString = [pscustomobject] @{
User = $user.username
Name = $user.fullname
Email = $user.email
Status = $user.status
PasswordStatus = $user.passwordstatus
Role = $user.role
}
$userResults += $userString
}
}
$userResults
}
Function New-VAMIUser {
<#
.NOTES
===========================================================================
Created by: William Lam
Organization: VMware
Blog: www.virtuallyghetto.com
Twitter: @lamw
===========================================================================
.SYNOPSIS
This function to create new VAMI local user using VAMI interface (5480)
for a VCSA node which can be an Embedded VCSA, External PSC or External VCSA.
.DESCRIPTION
Function to create a new VAMI local user
.EXAMPLE
Connect-CisServer -Server 192.168.1.51 -User administrator@vsphere.local -Password VMware1!
New-VAMIUser -name lamw -fullname "William Lam" -role "operator" -email "lamw@virtuallyghetto.com" -password "VMware1!"
#>
param(
[Parameter(
Mandatory=$true)
]
[String]$name,
[Parameter(
Mandatory=$true)
]
[String]$fullname,
[Parameter(
Mandatory=$true)
]
[ValidateSet("admin","operator","superAdmin")][String]$role,
[Parameter(
Mandatory=$false)
]
[String]$email="",
[Parameter(
Mandatory=$true)
]
[String]$password
)
$userAPI = Get-CisService 'com.vmware.appliance.techpreview.localaccounts.user'
$createSpec = $userAPI.Help.add.config.CreateExample()
$createSpec.username = $name
$createSpec.fullname = $fullname
$createSpec.role = $role
$createSpec.email = $email
$createSpec.password = [VMware.VimAutomation.Cis.Core.Types.V1.Secret]$password
try {
Write-Host "Creating new user $name ..."
$userAPI.add($createSpec)
} catch {
Write-Error $Error[0].exception.Message
}
}
Function Remove-VAMIUser {
<#
.NOTES
===========================================================================
Created by: William Lam
Organization: VMware
Blog: www.virtuallyghetto.com
Twitter: @lamw
===========================================================================
.SYNOPSIS
This function to remove VAMI local user using VAMI interface (5480)
for a VCSA node which can be an Embedded VCSA, External PSC or External VCSA.
.DESCRIPTION
Function to remove VAMI local user
.EXAMPLE
Connect-CisServer -Server 192.168.1.51 -User administrator@vsphere.local -Password VMware1!
Get-VAMIAccess
#>
param(
[Parameter(
Mandatory=$true)
]
[String]$name,
[Parameter(
Mandatory=$false)
]
[boolean]$confirm=$false
)
if(!$confirm) {
$answer = Read-Host -Prompt "Do you want to delete user $name (Y or N)"
if($answer -eq "Y" -or $answer -eq "y") {
$userAPI = Get-CisService 'com.vmware.appliance.techpreview.localaccounts.user'
try {
Write-Host "Deleting user $name ..."
$userAPI.delete($name)
} catch {
Write-Error $Error[0].exception.Message
}
}
}
}

View File

@@ -112,7 +112,7 @@ function Get-VmfsDatastoreIncrease
Datastore = $Datastore.Name
CanonicalName = $disk.CanonicalName
Model = "$($disk.Vendor.TrimEnd(' ')).$($disk.Model.TrimEnd(' ')).$($disk.Revision.TrimEnd(' '))"
DiskSizeGB = $partInfo[0].Layout.Total.BlockSize * $hdPartInfo[0].Layout.Total.Block / 1GB
DiskSizeGB = $partInfo[0].Layout.Total.BlockSize * $partInfo[0].Layout.Total.Block / 1GB
DiskBlocks = $partInfo[0].Layout.Total.Block
DiskBlockMB = $partInfo[0].Layout.Total.BlockSize/1MB
AvailableGB = [math]::Round($partMax - $partUsed, 2)
@@ -181,7 +181,7 @@ function New-VmfsDatastoreIncrease
{
$lun = $hScsiDisk | where{ $_.CanonicalName -eq $dsOpt.Spec.Extent.DiskName }
$partInfo = $hsSys.RetrieveDiskPartitionInfo($lun.DeviceName)
$partMax = ($vmfsExpOpt[0].Info.Layout.Partition | where{ $_.Type -eq 'VMFS' } | %{ ($_.End.Block - $_.Start.Block + 1) * $_.Start.BlockSize } |
$partMax = ($expOpt[0].Info.Layout.Partition | where{ $_.Type -eq 'VMFS' } | %{ ($_.End.Block - $_.Start.Block + 1) * $_.Start.BlockSize } |
Measure-Object -Sum | select -ExpandProperty Sum)/1GB
$partUsed = ($partInfo[0].Layout.Partition | where{ $_.Type -eq 'VMFS' } | %{ ($_.End.Block - $_.Start.Block + 1) * $_.Start.BlockSize } |
Measure-Object -Sum | select -ExpandProperty Sum)/1GB

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,21 @@
MIT License
Copyright (c) 2018 Markus Kraus
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

View File

@@ -0,0 +1,40 @@
VMware-vCD-Module PowerShell Module
===================================
![Invoke-MyOnBoarding](/media/Invoke-MyOnBoarding.png)
# About
## Project Owner:
Markus Kraus [@vMarkus_K](https://twitter.com/vMarkus_K)
MY CLOUD-(R)EVOLUTION [mycloudrevolution.com](http://mycloudrevolution.com/)
## Project WebSite:
[PowerCLI vCloud Director Customer Provisioning](https://mycloudrevolution.com/2017/06/13/powercli-vcloud-director-customer-provisioning/)
[PowerCLI Create vCloud Director Edge Gateway](https://mycloudrevolution.com/2017/06/27/powercli-create-vcloud-director-edge-gateway/)
## Project Documentation:
[Read the Docs - VMware-vCD-Module](http://vmware-vcd-module.readthedocs.io/)
## Project Description:
The 'VMware-vCD-Module' PowerShell Module is focused on the initial creation of VMware vCloud Director Objects like Org, Org User, Org VDC with External Networks or Edge Gateway.
All Functions in this Module can be used as standalone Cmdlet but also the ``Invoke-My OnBoarding`` Functions to process a JSON File and create all Objects at once.
### Fully tested Versions:
Powershell: v4, v5
PowerCLI: 6.5.1
VMware vCloud Director: 8.10.1

View File

@@ -0,0 +1,129 @@
#
# Modulmanifest f<>r das Modul "PSGet_VMware-vCD-Module"
#
# Generiert von: Markus
#
# Generiert am: 6/11/2017
#
@{
# Die diesem Manifest zugeordnete Skript- oder Bin<69>rmoduldatei.
# RootModule = ''
# Die Versionsnummer dieses Moduls
ModuleVersion = '1.3.0'
# ID zur eindeutigen Kennzeichnung dieses Moduls
GUID = '1ef8a2de-ca22-4c88-8cdb-e00f35007d2a'
# Autor dieses Moduls
Author = 'Markus Kraus'
# Unternehmen oder Hersteller dieses Moduls
CompanyName = 'mycloudrevolution.com'
# Urheberrechtserkl<6B>rung f<>r dieses Modul
Copyright = '(c) 2017 Markus. Alle Rechte vorbehalten.'
# Beschreibung der von diesem Modul bereitgestellten Funktionen
Description = 'This a POwerShell Module based on VMware PowerCLI vCloud Director Module to extend its function'
# Die f<>r dieses Modul mindestens erforderliche Version des Windows PowerShell-Moduls
# PowerShellVersion = ''
# Der Name des f<>r dieses Modul erforderlichen Windows PowerShell-Hosts
# PowerShellHostName = ''
# Die f<>r dieses Modul mindestens erforderliche Version des Windows PowerShell-Hosts
# PowerShellHostVersion = ''
# Die f<>r dieses Modul mindestens erforderliche Microsoft .NET Framework-Version
# DotNetFrameworkVersion = ''
# Die f<>r dieses Modul mindestens erforderliche Version der CLR (Common Language Runtime)
# CLRVersion = ''
# Die f<>r dieses Modul erforderliche Prozessorarchitektur ("Keine", "X86", "Amd64").
# ProcessorArchitecture = ''
# Die Module, die vor dem Importieren dieses Moduls in die globale Umgebung geladen werden m<>ssen
RequiredModules = @('VMware.VimAutomation.Cloud')
# Die Assemblys, die vor dem Importieren dieses Moduls geladen werden m<>ssen
# RequiredAssemblies = @()
# Die Skriptdateien (PS1-Dateien), die vor dem Importieren dieses Moduls in der Umgebung des Aufrufers ausgef<65>hrt werden.
# ScriptsToProcess = @()
# Die Typdateien (.ps1xml), die beim Importieren dieses Moduls geladen werden sollen
# TypesToProcess = @()
# Die Formatdateien (.ps1xml), die beim Importieren dieses Moduls geladen werden sollen
# FormatsToProcess = @()
# Die Module, die als geschachtelte Module des in "RootModule/ModuleToProcess" angegebenen Moduls importiert werden sollen.
NestedModules = @('functions\Invoke-MyOnBoarding.psm1',
'functions\New-MyEdgeGateway.psm1',
'functions\New-MyOrg.psm1',
'functions\New-MyOrgAdmin.psm1',
'functions\New-MyOrgVdc.psm1',
'functions\New-MyOrgNetwork.psm1'
)
# Aus diesem Modul zu exportierende Funktionen
FunctionsToExport = 'Invoke-MyOnBoarding', 'New-MyEdgeGateway', 'New-MyOrg', 'New-MyOrgAdmin', 'New-MyOrgVdc', 'New-MyOrgNetwork'
# Aus diesem Modul zu exportierende Cmdlets
CmdletsToExport = '*'
# Die aus diesem Modul zu exportierenden Variablen
VariablesToExport = '*'
# Aus diesem Modul zu exportierende Aliase
AliasesToExport = '*'
# Aus diesem Modul zu exportierende DSC-Ressourcen
# DscResourcesToExport = @()
# Liste aller Module in diesem Modulpaket
# ModuleList = @()
# Liste aller Dateien in diesem Modulpaket
# FileList = @()
# Die privaten Daten, die an das in "RootModule/ModuleToProcess" angegebene Modul <20>bergeben werden sollen. Diese k<>nnen auch eine PSData-Hashtabelle mit zus<75>tzlichen von PowerShell verwendeten Modulmetadaten enthalten.
PrivateData = @{
PSData = @{
# Tags applied to this module. These help with module discovery in online galleries.
Tags = @('VMware', 'vCloud', 'PowerCLI', 'vCloudDirector', 'Automation', 'EdgeGateway', 'OrgNetwork')
# A URL to the license for this module.
LicenseUri = 'https://github.com/mycloudrevolution/VMware-vCD-Module/blob/master/LICENSE'
# A URL to the main website for this project.
ProjectUri = 'https://github.com/mycloudrevolution/VMware-vCD-Module'
# A URL to an icon representing this module.
IconUri = 'https://github.com/mycloudrevolution/VMware-vCD-Module/blob/master/media/vCD_Small.png'
# ReleaseNotes of this module
# ReleaseNotes = ''
# External dependent modules of this module
ExternalModuleDependencies = 'VMware.VimAutomation.Cloud'
} # End of PSData hashtable
} # End of PrivateData hashtable
# HelpInfo-URI dieses Moduls
# HelpInfoURI = ''
# Standardpr<70>fix f<>r Befehle, die aus diesem Modul exportiert werden. Das Standardpr<70>fix kann mit "Import-Module -Prefix" <20>berschrieben werden.
# DefaultCommandPrefix = ''
}

View File

@@ -0,0 +1,30 @@
{
"Org": {
"Name":"TestOrg",
"FullName": "Test Org",
"Description":"Automation Test Org"
},
"OrgAdmin": {
"Name":"TestOrgAdmin",
"Pasword": "myPassword1!",
"FullName":"Test OrgAdmin",
"EmailAddress":"test@admin.org"
},
"OrgVdc": {
"Name":"TestOrgVdc",
"FixedSize": "M",
"CPULimit": "1000",
"MEMLimit":"1024",
"StorageLimit":"1024",
"StorageProfile":"Standard-DC01",
"ProviderVDC":"Provider-VDC-DC01",
"NetworkPool":"Provider-VDC-DC01-NetPool",
"ExternalNetwork": "External-OrgVdcNet",
"EdgeGateway": "Yes",
"IPAddress":"192.168.100.1",
"SubnetMask":"255.255.255.0",
"Gateway":"192.168.100.254",
"IPRangeStart":"192.168.100.2",
"IPRangeEnd":"192.168.100.3"
}
}

View File

@@ -0,0 +1,193 @@
Function Invoke-MyOnBoarding {
<#
.SYNOPSIS
Creates all vCD Objecst for a new IAAS Customer
.DESCRIPTION
Creates all vCD Objects for a new IAAS Customer
All Objects are:
* Org
* Default Org Admin
* Org VDC
** Private Catalog
** Optional Bridged Network
JSON Config Example:
{
"Org": {
"Name":"TestOrg",
"FullName": "Test Org",
"Description":"Automation Test Org"
},
"OrgAdmin": {
"Name":"TestOrgAdmin",
"Pasword": "myPassword1!",
"FullName":"Test OrgAdmin",
"EmailAddress":"test@admin.org"
},
"OrgVdc": {
"Name":"TestOrgVdc",
"FixedSize": "M",
"CPULimit": "1000",
"MEMLimit":"1000",
"StorageLimit":"1000",
"StorageProfile":"Standard-DC01",
"ProviderVDC":"Provider-VDC-DC01",
"NetworkPool":"Provider-VDC-DC01-NetPool",
"ExternalNetwork": "External_OrgVdcNet",
"EdgeGateway": "Yes",
"IPAddress":"192.168.100.1",
"SubnetMask":"255.255.255.0",
"Gateway":"192.168.100.254",
"IPRangeStart":"192.168.100.2",
"IPRangeEnd":"192.168.100.3"
}
}
.NOTES
File Name : Invoke-MyOnBoarding.ps1
Author : Markus Kraus
Version : 1.3
State : Ready
.LINK
https://mycloudrevolution.com/
.EXAMPLE
Invoke-MyOnBoarding -ConfigFile ".\OnBoarding.json" -Enabled:$true
.EXAMPLE
Invoke-MyOnBoarding -ConfigFile ".\OnBoarding.json" -Enabled:$false
.PARAMETER ConfigFile
Full Path to the JSON Config File
.PARAMETER Enabled
Should the Customer be enabled after creation
Default: $False
#>
Param (
[Parameter(Mandatory=$True, ValueFromPipeline=$False, HelpMessage="Full Path to the JSON Config File")]
[ValidateNotNullorEmpty()]
[String] $ConfigFile,
[Parameter(Mandatory=$False, ValueFromPipeline=$False, HelpMessage="Should the Customer be enabled after creation")]
[ValidateNotNullorEmpty()]
[Switch]$Enabled
)
Process {
$Valid = $true
Write-Verbose "## Import JSON Config"
Write-Host "$(Get-Date -Format "yyyy-MM-dd HH:mm:ss") Importing JSON Config...`n"
$Configs = Get-Content -Raw -Path $ConfigFile -ErrorAction Continue | ConvertFrom-Json -ErrorAction Continue
if (!($Configs)) {
$Valid = $false
Write-Host "$(Get-Date -Format "yyyy-MM-dd HH:mm:ss") Importing JSON Config Failed" -ForegroundColor Red
}
else {
Write-Host "$(Get-Date -Format "yyyy-MM-dd HH:mm:ss") Importing JSON Config OK" -ForegroundColor Green
}
if ($Valid) {
try{
Write-Verbose "## Create Org"
Write-Host "$(Get-Date -Format "yyyy-MM-dd HH:mm:ss") Creating new Org...`n" -ForegroundColor Yellow
$Trash = New-MyOrg -Name $Configs.Org.Name -FullName $Configs.Org.Fullname -Description $Configs.Org.Description -Enabled:$Enabled
Write-Host "$(Get-Date -Format "yyyy-MM-dd HH:mm:ss") Creating new Org OK" -ForegroundColor Green
Get-Org -Name $Configs.Org.Name | Select-Object Name, FullName, Enabled | Format-Table -AutoSize
}
catch {
$Valid = $false
Write-Host "$(Get-Date -Format "yyyy-MM-dd HH:mm:ss") Creating new Org Failed" -ForegroundColor Red
}
}
if ($Valid) {
try{
Write-Verbose "## Create OrgAdmin"
Write-Host "$(Get-Date -Format "yyyy-MM-dd HH:mm:ss") Creating new OrgAdmin...`n" -ForegroundColor Yellow
$Trash = New-MyOrgAdmin -Name $Configs.OrgAdmin.Name -Pasword $Configs.OrgAdmin.Pasword -FullName $Configs.OrgAdmin.FullName -EmailAddress $Configs.OrgAdmin.EmailAddress -Org $Configs.Org.Name -Enabled:$Enabled
Write-Host "$(Get-Date -Format "yyyy-MM-dd HH:mm:ss") Creating new OrgAdmin OK" -ForegroundColor Green
Get-CIUser -Org $Configs.Org.Name -Name $Configs.OrgAdmin.Name | Select-Object Name, FullName, Email | Format-Table -AutoSize
}
catch {
$Valid = $false
Write-Host "$(Get-Date -Format "yyyy-MM-dd HH:mm:ss") Creating new OrgAdmin Failed" -ForegroundColor Red
}
}
if ($Valid) {
try{
Write-Verbose "## Create OrgVdc"
Write-Host "$(Get-Date -Format "yyyy-MM-dd HH:mm:ss") Creating new OrgVdc...`n" -ForegroundColor Yellow
if ($Configs.OrgVdc.FixedSize){
Write-Host "Fixed Size (T-Shirt Size) '$($Configs.OrgVdc.FixedSize)' Org VDC Requested!"
switch ($Configs.OrgVdc.FixedSize) {
M {
[String]$CPULimit = 36000
[String]$MEMLimit = 122880
[String]$StorageLimit = 1048576
}
L {
[String]$CPULimit = 36000
[String]$MEMLimit = 245760
[String]$StorageLimit = 1048576
}
default {throw "Invalid T-Shirt Size!"}
}
}
else{
Write-Host "Custom Org VDC Size Requested!"
$CPULimit = $Configs.OrgVdc.CPULimit
$MEMLimit = $Configs.OrgVdc.MEMLimit
$StorageLimit = $Configs.OrgVdc.StorageLimit
}
if ($Configs.OrgVdc.ExternalNetwork -and $Configs.OrgVdc.EdgeGateway -like "Yes"){
Write-Host "Edge Gateway for Org VDC '$($Configs.OrgVdc.Name)' Requested!"
$Trash = New-MyOrgVdc -Name $Configs.OrgVdc.Name -CPULimit $CPULimit -MEMLimit $MEMLimit -StorageLimit $StorageLimit -Networkpool $Configs.OrgVdc.NetworkPool `
-StorageProfile $Configs.OrgVdc.StorageProfile -ProviderVDC $Configs.OrgVdc.ProviderVDC -Org $Configs.Org.Name -Enabled:$Enabled
$EdgeName = $Configs.Org.Name + "-ESG01"
$Trash = New-MyEdgeGateway -Name $EdgeName -OrgVDCName $Configs.OrgVdc.Name -Orgname $Configs.Org.Name -ExternalNetwork $Configs.OrgVdc.ExternalNetwork `
-IPAddress $Configs.OrgVdc.IPAddress -SubnetMask $Configs.OrgVdc.SubnetMask -Gateway $Configs.OrgVdc.Gateway -IPRangeStart $Configs.OrgVdc.IPRangeStart -IPRangeEnd $Configs.OrgVdc.IPRangeEnd
}
elseif ($Configs.OrgVdc.ExternalNetwork -and $Configs.OrgVdc.EdgeGateway -like "No"){
Write-Host "External Network for Org VDC '$($Configs.OrgVdc.Name)' Requested!"
$Trash = New-MyOrgVdc -Name $Configs.OrgVdc.Name -CPULimit $CPULimit -MEMLimit $MEMLimit -StorageLimit $StorageLimit -Networkpool $Configs.OrgVdc.NetworkPool `
-StorageProfile $Configs.OrgVdc.StorageProfile -ProviderVDC $Configs.OrgVdc.ProviderVDC -ExternalNetwork $Configs.OrgVdc.ExternalNetwork -Org $Configs.Org.Name -Enabled:$Enabled
}
else {
Write-Host "No external Connection for Org VDC '$($Configs.OrgVdc.Name)' Requested!"
$Trash = New-PecOrgVdc -Name $Configs.OrgVdc.Name -CPULimit $CPULimit -MEMLimit $MEMLimit -StorageLimit $StorageLimit -Networkpool $ProVdcNetworkPool.Name `
-StorageProfile $Configs.OrgVdc.StorageProfile -ProviderVDC $Configs.OrgVdc.ProviderVDC -Org $Configs.Org.Name -Enabled:$Enabled
}
Write-Host "$(Get-Date -Format "yyyy-MM-dd HH:mm:ss") Creating new OrgVdc OK" -ForegroundColor Green
Get-OrgVdc -Org $Configs.Org.Name -Name $Configs.OrgVdc.Name | Select-Object Name, Enabled, CpuAllocationGhz, MemoryLimitGB, StorageLimitGB, AllocationModel, ThinProvisioned, UseFastProvisioning, `
@{N="StorageProfile";E={$_.ExtensionData.VdcStorageProfiles.VdcStorageProfile.Name}}, `
@{N='VCpuInMhz';E={$_.ExtensionData.VCpuInMhz}} | Format-Table -AutoSize
if ($Configs.OrgVdc.EdgeGateway -like "Yes"){
Search-Cloud -QueryType EdgeGateway -Name $EdgeName | Select Name, IsBusy, GatewayStatus, HaStatus | ft -AutoSize
}
}
catch {
$Valid = $false
Write-Host "$(Get-Date -Format "yyyy-MM-dd HH:mm:ss") Creating new OrgVdc Failed" -ForegroundColor Red
}
}
Write-Output "Overall Execution was Valid: $Valid"
}
}

View File

@@ -0,0 +1,165 @@
Function New-MyEdgeGateway {
<#
.SYNOPSIS
Creates a new Edge Gateway with Default Parameters
.DESCRIPTION
Creates a new Edge Gateway with Default Parameters
Default Parameters are:
* HA State
* DNS Relay
.NOTES
File Name : New-MyEdgeGateway.ps1
Author : Markus Kraus
Version : 1.1
State : Ready
.LINK
https://mycloudrevolution.com/
.EXAMPLE
New-MyEdgeGateway -Name "TestEdge" -OrgVDCName "TestVDC" -OrgName "TestOrg" -Size compact -ExternalNetwork "ExternalNetwork" -IPAddress "192.168.100.1" -SubnetMask "255.255.255.0" -Gateway "192.168.100.254" -IPRangeStart ""192.168.100.2" -IPRangeEnd ""192.168.100.3" -Verbose
.PARAMETER Name
Name of the New Edge Gateway as String
.PARAMETER OrgVDCName
OrgVDC where the new Edge Gateway should be created as string
.PARAMETER OrgName
Org where the new Edge Gateway should be created as string
.PARAMETER Size
Size of the new Edge Gateway as string
.PARAMETER ExternalNetwork
External Network of the new Edge Gateway as String
.PARAMETER IPAddress
IP Address of the New Edge Gateway as IP Address
.PARAMETER SubnetMask
Subnet Mask of the New Edge Gateway as IP Address
.PARAMETER Gateway
Gateway of the New Edge Gateway as IP Address
.PARAMETER IPRangeStart
Sub Allocation IP Range Start of the New Edge Gateway as IP Address
.PARAMETER IPRangeEnd
Sub Allocation IP Range End of the New Edge Gateway as IP Address
.PARAMETER Timeout
Timeout for the Edge Gateway to get Ready
Default: 120s
#>
Param (
[Parameter(Mandatory=$True, ValueFromPipeline=$False, HelpMessage="Name of the New Edge Gateway as String")]
[ValidateNotNullorEmpty()]
[String] $Name,
[Parameter(Mandatory=$True, ValueFromPipeline=$False, HelpMessage="OrgVDC where the new Edge Gateway should be created as string")]
[ValidateNotNullorEmpty()]
[String] $OrgVdcName,
[Parameter(Mandatory=$True, ValueFromPipeline=$False, HelpMessage="Org where the new Edge Gateway should be created as string")]
[ValidateNotNullorEmpty()]
[String] $OrgName,
[Parameter(Mandatory=$True, ValueFromPipeline=$False, HelpMessage="Size of the new Edge Gateway as string")]
[ValidateNotNullorEmpty()]
[ValidateSet("compact","full")]
[String] $Size,
[Parameter(Mandatory=$True, ValueFromPipeline=$False, HelpMessage="External Network of the New Edge Gateway as String")]
[ValidateNotNullorEmpty()]
[String] $ExternalNetwork,
[Parameter(Mandatory=$True, ValueFromPipeline=$False, HelpMessage="IP Address of the New Edge Gateway as IP Address")]
[ValidateNotNullorEmpty()]
[IPAddress] $IPAddress,
[Parameter(Mandatory=$True, ValueFromPipeline=$False, HelpMessage="Subnet Mask of the New Edge Gateway as IP Address")]
[ValidateNotNullorEmpty()]
[IPAddress] $SubnetMask,
[Parameter(Mandatory=$True, ValueFromPipeline=$False, HelpMessage="Gateway of the New Edge Gateway as IP Address")]
[ValidateNotNullorEmpty()]
[IPAddress] $Gateway,
[Parameter(Mandatory=$True, ValueFromPipeline=$False, HelpMessage="Sub Allocation IP Range Start the New Edge Gateway as IP Address")]
[ValidateNotNullorEmpty()]
[IPAddress] $IPRangeStart,
[Parameter(Mandatory=$True, ValueFromPipeline=$False, HelpMessage="Sub Allocation IP Range End the New Edge Gateway as IP Address")]
[ValidateNotNullorEmpty()]
[IPAddress] $IPRangeEnd,
[Parameter(Mandatory=$False, ValueFromPipeline=$False,HelpMessage="Timeout for the Edge Gateway to get Ready")]
[ValidateNotNullorEmpty()]
[int] $Timeout = 120
)
Process {
## Get Org vDC
Write-Verbose "Get Org vDC"
[Array] $orgVdc = Get-Org -Name $OrgName | Get-OrgVdc -Name $OrgVdcName
if ( $orgVdc.Count -gt 1) {
throw "Multiple OrgVdcs found!"
}
elseif ( $orgVdc.Count -lt 1) {
throw "No OrgVdc found!"
}
## Get External Network
Write-Verbose "Get External Network"
$extNetwork = Get-ExternalNetwork | Get-CIView -Verbose:$False | Where-Object {$_.name -eq $ExternalNetwork}
## Build EdgeGatway Configuration
Write-Verbose "Build EdgeGatway Configuration"
$EdgeGateway = New-Object VMware.VimAutomation.Cloud.Views.Gateway
$EdgeGateway.Name = $Name
$EdgeGateway.Configuration = New-Object VMware.VimAutomation.Cloud.Views.GatewayConfiguration
#$EdgeGateway.Configuration.BackwardCompatibilityMode = $false
$EdgeGateway.Configuration.GatewayBackingConfig = $Size
$EdgeGateway.Configuration.UseDefaultRouteForDnsRelay = $false
$EdgeGateway.Configuration.HaEnabled = $false
$EdgeGateway.Configuration.EdgeGatewayServiceConfiguration = New-Object VMware.VimAutomation.Cloud.Views.GatewayFeatures
$EdgeGateway.Configuration.GatewayInterfaces = New-Object VMware.VimAutomation.Cloud.Views.GatewayInterfaces
$EdgeGateway.Configuration.GatewayInterfaces.GatewayInterface = New-Object VMware.VimAutomation.Cloud.Views.GatewayInterface
$EdgeGateway.Configuration.GatewayInterfaces.GatewayInterface[0].name = $extNetwork.Name
$EdgeGateway.Configuration.GatewayInterfaces.GatewayInterface[0].DisplayName = $extNetwork.Name
$EdgeGateway.Configuration.GatewayInterfaces.GatewayInterface[0].Network = $extNetwork.Href
$EdgeGateway.Configuration.GatewayInterfaces.GatewayInterface[0].InterfaceType = "uplink"
$EdgeGateway.Configuration.GatewayInterfaces.GatewayInterface[0].UseForDefaultRoute = $true
$EdgeGateway.Configuration.GatewayInterfaces.GatewayInterface[0].ApplyRateLimit = $false
$ExNetexternalSubnet = New-Object VMware.VimAutomation.Cloud.Views.SubnetParticipation
$ExNetexternalSubnet.Gateway = $Gateway.IPAddressToString
$ExNetexternalSubnet.Netmask = $SubnetMask.IPAddressToString
$ExNetexternalSubnet.IpAddress = $IPAddress.IPAddressToString
$ExNetexternalSubnet.IpRanges = New-Object VMware.VimAutomation.Cloud.Views.IpRanges
$ExNetexternalSubnet.IpRanges.IpRange = New-Object VMware.VimAutomation.Cloud.Views.IpRange
$ExNetexternalSubnet.IpRanges.IpRange[0].StartAddress = $IPRangeStart.IPAddressToString
$ExNetexternalSubnet.IpRanges.IpRange[0].EndAddress = $IPRangeEnd.IPAddressToString
$EdgeGateway.Configuration.GatewayInterfaces.GatewayInterface[0].SubnetParticipation = $ExNetexternalSubnet
## Create EdgeGatway
Write-Verbose "Create EdgeGatway"
$CreateEdgeGateway = $orgVdc.ExtensionData.CreateEdgeGateway($EdgeGateway)
## Wait for EdgeGatway to become Ready
Write-Verbose "Wait for EdgeGatway to become Ready"
while((Search-Cloud -QueryType EdgeGateway -Name $Name -Verbose:$False).IsBusy -eq $True){
$i++
Start-Sleep 5
if($i -gt $Timeout) { Write-Error "Creating Edge Gateway."; break}
Write-Progress -Activity "Creating Edge Gateway" -Status "Wait for Edge to become Ready..."
}
Write-Progress -Activity "Creating Edge Gateway" -Completed
Start-Sleep 1
Search-Cloud -QueryType EdgeGateway -Name $Name | Select-Object Name, IsBusy, GatewayStatus, HaStatus | Format-Table -AutoSize
}
}

View File

@@ -0,0 +1,105 @@
Function New-MyOrg {
<#
.SYNOPSIS
Creates a new vCD Org with Default Parameters
.DESCRIPTION
Creates a new vCD Org with Default Parameters.
Default Parameters are:
* Catalog Publishing
* Catalog Subscription
* VM Quota
* Stored VM Quota
* VM Lease Time
* Stored VM Lease Time
* Password Policy Settings
.NOTES
File Name : New-MyOrg.ps1
Author : Markus Kraus
Version : 1.1
State : Ready
.LINK
https://mycloudrevolution.com/
.EXAMPLE
New-MyOrg -Name "TestOrg" -FullName "Test Org" -Description "PowerCLI Test Org"
.PARAMETER Name
Name of the New Org as String
.PARAMETER FullName
Full Name of the New Org as String
.PARAMETER Description
Description of the New Org as String
.PARAMETER Enabled
Should the New Org be enabled after creation
Default:$false
#>
Param (
[Parameter(Mandatory=$True, ValueFromPipeline=$False, HelpMessage="Name of the New Org as string")]
[ValidateNotNullorEmpty()]
[String] $Name,
[Parameter(Mandatory=$True, ValueFromPipeline=$False, HelpMessage="Full Name of the New Org as string")]
[ValidateNotNullorEmpty()]
[String] $FullName,
[Parameter(Mandatory=$False, ValueFromPipeline=$False, HelpMessage="Description of the New Org as string")]
[ValidateNotNullorEmpty()]
[String] $Description,
[Parameter(Mandatory=$False, ValueFromPipeline=$False, HelpMessage="Should the New Org be enabled after creation")]
[ValidateNotNullorEmpty()]
[Switch]$Enabled
)
Process {
$vcloud = $DefaultCIServers[0].ExtensionData
## Create Objects
$AdminOrg = New-Object VMware.VimAutomation.Cloud.Views.AdminOrg
$orgGeneralSettings = New-Object VMware.VimAutomation.Cloud.Views.OrgGeneralSettings
$orgOrgLeaseSettings = New-Object VMware.VimAutomation.Cloud.Views.OrgLeaseSettings
$orgOrgVAppTemplateLeaseSettings = New-Object VMware.VimAutomation.Cloud.Views.OrgVAppTemplateLeaseSettings
$orgOrgPasswordPolicySettings = New-Object VMware.VimAutomation.Cloud.Views.OrgPasswordPolicySettings
$orgSettings = New-Object VMware.VimAutomation.Cloud.Views.OrgSettings
## Admin Settings
$adminOrg.Name = $name
$adminOrg.FullName = $FullName
$adminOrg.Description = $description
$adminOrg.IsEnabled = $Enabled
## Org Setting
### General Org Settings
$orgGeneralSettings.CanPublishCatalogs = $False
$orgGeneralSettings.CanPublishExternally = $False
$orgGeneralSettings.CanSubscribe = $True
$orgGeneralSettings.DeployedVMQuota = 0
$orgGeneralSettings.StoredVmQuota = 0
$orgSettings.OrgGeneralSettings = $orgGeneralSettings
### vApp Org Setting
$orgOrgLeaseSettings.DeleteOnStorageLeaseExpiration = $false
$orgOrgLeaseSettings.DeploymentLeaseSeconds = 0
$orgOrgLeaseSettings.StorageLeaseSeconds = 0
$orgSettings.VAppLeaseSettings = $orgOrgLeaseSettings
### vApp Template Org Setting
$orgOrgVAppTemplateLeaseSettings.DeleteOnStorageLeaseExpiration = $false
$orgOrgVAppTemplateLeaseSettings.StorageLeaseSeconds = 0
$orgSettings.VAppTemplateLeaseSettings = $orgOrgVAppTemplateLeaseSettings
### PasswordPolicySettings Org Setting
$orgOrgPasswordPolicySettings.AccountLockoutEnabled = $True
$orgOrgPasswordPolicySettings.InvalidLoginsBeforeLockout = 5
$orgOrgPasswordPolicySettings.AccountLockoutIntervalMinutes = 30
$orgSettings.OrgPasswordPolicySettings = $orgOrgPasswordPolicySettings
$adminOrg.Settings = $orgSettings
$CreateOrg = $vcloud.CreateOrg($adminOrg)
Get-Org -Name $name | Format-Table -AutoSize
}
}

View File

@@ -0,0 +1,89 @@
Function New-MyOrgAdmin {
<#
.SYNOPSIS
Creates a new vCD Org Admin with Default Parameters
.DESCRIPTION
Creates a new vCD Org Admin with Default Parameters
Default Parameters are:
* User Role
.NOTES
File Name : New-MyOrgAdmin.ps1
Author : Markus Kraus
Version : 1.1
State : Ready
.LINK
https://mycloudrevolution.com/
.EXAMPLE
New-MyOrgAdmin -Name "OrgAdmin" -Pasword "Anfang!!" -FullName "Org Admin" -EmailAddress "OrgAdmin@TestOrg.local" -Org "TestOrg"
.PARAMETER Name
Name of the New Org Admin as String
.PARAMETER FullName
Full Name of the New Org Admin as String
.PARAMETER Password
Password of the New Org Admin as String
.PARAMETER EmailAddress
EmailAddress of the New Org Admin as String
.PARAMETER Enabled
Should the New Org be enabled after creation
Default:$false
.PARAMETER Org
Org where the new Org Admin should be created as string
#>
Param (
[Parameter(Mandatory=$True, ValueFromPipeline=$False, HelpMessage="Name of the New Org Admin as String")]
[ValidateNotNullorEmpty()]
[String] $Name,
[Parameter(Mandatory=$True, ValueFromPipeline=$False, HelpMessage="Password of the New Org Admin as String")]
[ValidateNotNullorEmpty()]
[String] $Pasword,
[Parameter(Mandatory=$True, ValueFromPipeline=$False, HelpMessage="Full Name of the New Org Admin as String")]
[ValidateNotNullorEmpty()]
[String] $FullName,
[Parameter(Mandatory=$True, ValueFromPipeline=$False, HelpMessage="EmailAddress of the New Org Admin as String")]
[ValidateNotNullorEmpty()]
[String] $EmailAddress,
[Parameter(Mandatory=$True, ValueFromPipeline=$False, HelpMessage="Org where the new Org Admin should be created as string")]
[ValidateNotNullorEmpty()]
[String] $Org,
[Parameter(Mandatory=$False, ValueFromPipeline=$False, HelpMessage="Should the New Org be enabled after creation")]
[ValidateNotNullorEmpty()]
[Switch]$Enabled
)
Process {
## Create Objects
$OrgED = (Get-Org $Org).ExtensionData
$orgAdminUser = New-Object VMware.VimAutomation.Cloud.Views.User
## Settings
$orgAdminUser.Name = $Name
$orgAdminUser.FullName = $FullName
$orgAdminUser.EmailAddress = $EmailAddress
$orgAdminUser.Password = $Pasword
$orgAdminUser.IsEnabled = $Enabled
$vcloud = $DefaultCIServers[0].ExtensionData
## Find Role
$orgAdminRole = $vcloud.RoleReferences.RoleReference | Where-Object {$_.Name -eq "Organization Administrator"}
$orgAdminUser.Role = $orgAdminRole
## Create User
$user = $orgED.CreateUser($orgAdminUser)
Get-CIUser -Org $Org -Name $Name | Format-Table -AutoSize
}
}

View File

@@ -0,0 +1,166 @@
Function New-MyOrgNetwork {
<#
.SYNOPSIS
Creates a new Org Network with Default Parameters
.DESCRIPTION
.NOTES
File Name : New-MyOrgNetwork.ps1
Author : Markus Kraus
Version : 1.1
State : Ready
.LINK
https://mycloudrevolution.com
.EXAMPLE
New-MyOrgNetwork -Name Test -OrgVdcName "Test-OrgVDC" -OrgName "Test-Org" -EdgeName "Test-OrgEdge" -SubnetMask 255.255.255.0 -Gateway 192.168.66.1 -IPRangeStart 192.168.66.100 -IPRangeEnd 192.168.66.200
.EXAMPLE
New-MyOrgNetwork -Name Test -OrgVdcName "Test-OrgVDC" -OrgName "Test-Org" -EdgeName "Test-OrgEdge" -SubnetMask 255.255.255.0 -Gateway 192.168.66.1 -IPRangeStart 192.168.66.100 -IPRangeEnd 192.168.66.200 -Shared:$False
.EXAMPLE
$params = @{ 'Name' = 'Test';
'OrgVdcName'= 'Test-OrgVDC';
'OrgName'='Test-Org';
'EdgeName'='Test-OrgEdge';
'SubnetMask' = '255.255.255.0';
'Gateway' = '192.168.66.1';
'IPRangeStart' = '192.168.66.100';
'IPRangeEnd' = '192.168.66.200'
}
New-MyOrgNetwork @params -Verbose
.PARAMETER Name
Name of the New Org Network as String
.PARAMETER OrgVDCName
OrgVDC where the new Org Network should be created as string
.PARAMETER OrgName
Org where the newOrg Networkshould be created as string
.PARAMETER EdgeName
Edge Gateway Name for the new Org Network as String
.PARAMETER SubnetMask
Subnet Mask of the New Org Network as IP Address
.PARAMETER Gateway
Gateway of the New Org Network as IP Address
.PARAMETER IPRangeStart
IP Range Start of the New Org Network as IP Address
.PARAMETER IPRangeEnd
IP Range End of the New Org Network as IP Address
.PARAMETER Shared
Switch for Shared OrgVDC Network
Default: $True
.PARAMETER Timeout
Timeout for the Org Network to become Ready
Default: 120s
#>
Param (
[Parameter(Mandatory=$True, ValueFromPipeline=$False, HelpMessage="Name of the New Org Network as String")]
[ValidateNotNullorEmpty()]
[String] $Name,
[Parameter(Mandatory=$True, ValueFromPipeline=$False, HelpMessage="OrgVDC where the new Org Network should be created as string")]
[ValidateNotNullorEmpty()]
[String] $OrgVdcName,
[Parameter(Mandatory=$True, ValueFromPipeline=$False, HelpMessage="Org where the new Org Network should be created as string")]
[ValidateNotNullorEmpty()]
[String] $OrgName,
[Parameter(Mandatory=$True, ValueFromPipeline=$False, HelpMessage="Edge Gateway Name for the new Org Network as String")]
[ValidateNotNullorEmpty()]
[String] $EdgeName,
[Parameter(Mandatory=$True, ValueFromPipeline=$False, HelpMessage="Subnet Mask of the New Org Network as IP Address")]
[ValidateNotNullorEmpty()]
[IPAddress] $SubnetMask,
[Parameter(Mandatory=$True, ValueFromPipeline=$False, HelpMessage="Gateway of the New Org Network as IP Address")]
[ValidateNotNullorEmpty()]
[IPAddress] $Gateway,
[Parameter(Mandatory=$True, ValueFromPipeline=$False, HelpMessage="IP Range Start the New Org Network as IP Address")]
[ValidateNotNullorEmpty()]
[IPAddress] $IPRangeStart,
[Parameter(Mandatory=$True, ValueFromPipeline=$False, HelpMessage="IP Range End the New Org Network as IP Address")]
[ValidateNotNullorEmpty()]
[IPAddress] $IPRangeEnd,
[Parameter(Mandatory=$False, ValueFromPipeline=$False, HelpMessage="Switch for Shared OrgVDC Network")]
[ValidateNotNullorEmpty()]
[Bool] $Shared = $True,
[Parameter(Mandatory=$False, ValueFromPipeline=$False,HelpMessage="Timeout for the Org Network to become Ready")]
[ValidateNotNullorEmpty()]
[int] $Timeout = 120
)
Process {
## Get Org vDC
Write-Verbose "Get Org vDC"
[Array] $orgVdc = Get-Org -Name $OrgName | Get-OrgVdc -Name $OrgVdcName
if ( $orgVdc.Count -gt 1) {
throw "Multiple OrgVdcs found!"
}
elseif ( $orgVdc.Count -lt 1) {
throw "No OrgVdc found!"
}
$orgVdcView = $orgVdc| Get-CIView
## Get EdgeGateway
Write-Verbose "Get EdgeGateway"
[Array] $edgeGateway = Search-Cloud -QueryType EdgeGateway -Name $EdgeName | Get-CIView
if ( $edgeGateway.Count -gt 1) {
throw "Multiple EdgeGateways found!"
}
elseif ( $edgeGateway.Count -lt 1) {
throw "No EdgeGateway found!"
}
## Define Org Network
Write-Verbose "Define Org Network"
$OrgNetwork = new-object vmware.vimautomation.cloud.views.orgvdcnetwork
$OrgNetwork.name = $Name
$OrgNetwork.edgegateway = $edgeGateway.id
$OrgNetwork.isshared = $Shared
$OrgNetwork.configuration = new-object vmware.vimautomation.cloud.views.networkconfiguration
$OrgNetwork.configuration.fencemode = "natRouted"
$OrgNetwork.configuration.ipscopes = new-object vmware.vimautomation.cloud.views.ipscopes
$Scope = new-object vmware.vimautomation.cloud.views.ipScope
$Scope.gateway = $Gateway
$Scope.netmask = $SubnetMask
$Scope.ipranges = new-object vmware.vimautomation.cloud.views.ipranges
$Scope.ipranges.iprange = new-object vmware.vimautomation.cloud.views.iprange
$Scope.ipranges.iprange[0].startaddress = $IPRangeStart
$Scope.ipranges.iprange[0].endaddress = $IPRangeEnd
$OrgNetwork.configuration.ipscopes.ipscope += $Scope
## Create Org Network
Write-Verbose "Create Org Network"
$CreateOrgNetwork = $orgVdcView.CreateNetwork($OrgNetwork)
## Wait for Org Network to become Ready
Write-Verbose "Wait for Org Network to become Ready"
while(!(Get-OrgVdcNetwork -Id $CreateOrgNetwork.Id -ErrorAction SilentlyContinue)){
$i++
Start-Sleep 5
if($i -gt $Timeout) { Write-Error "Creating Org Network."; break}
Write-Progress -Activity "Creating Org Network" -Status "Wait for Network to become Ready..."
}
Write-Progress -Activity "Creating Org Network" -Completed
Start-Sleep 1
Get-OrgVdcNetwork -Id $CreateOrgNetwork.Id | Select-Object Name, OrgVdc, NetworkType, DefaultGateway, Netmask, StaticIPPool, @{ N='isShared'; E = {$_.ExtensionData.isShared} } | Format-Table -AutoSize
}
}

View File

@@ -0,0 +1,265 @@
Function New-MyOrgVdc {
<#
.SYNOPSIS
Creates a new vCD Org VDC with Default Parameters
.DESCRIPTION
Creates a new vCD Org VDC with Default Parameters
Default Parameters are:
* Network Quota
* VM Quota
* 'vCpu In Mhz'
* Fast Provisioning
* Thin Provisioning
* private Catalog
.NOTES
File Name : New-MyOrgVdc.ps1
Author : Markus Kraus
Version : 1.3
State : Ready
.LINK
https://mycloudrevolution.com/
.EXAMPLE
New-MyOrgVdc -Name "TestVdc" -AllocationModel AllocationPool -CPULimit 1000 -MEMLimit 1000 -StorageLimit 1000 -StorageProfile "Standard-DC01" -NetworkPool "NetworkPool-DC01" -ProviderVDC "Provider-VDC-DC01" -Org "TestOrg" -ExternalNetwork "External_OrgVdcNet"
.EXAMPLE
New-MyOrgVdc -Name "TestVdc" -AllocationModel AllocationVApp -StorageLimit 1000 -StorageProfile "Standard-DC01" -NetworkPool "NetworkPool-DC01" -ProviderVDC "Provider-VDC-DC01" -Org "TestOrg"
.PARAMETER Name
Name of the New Org VDC as String
.PARAMETER AllocationModel
Allocation Model of the New Org VDC as String
.PARAMETER CPULimit
CPU Limit (MHz) of the New Org VDC as String
Default: 0 (Unlimited)
Note: If AllocationModel is not AllocationVApp (Pay as you go), a limit needs to be set
.PARAMETER MEMLimit
Memory Limit (MB) of the New Org VDC as String
Default: 0 (Unlimited)
Note: If AllocationModel is not AllocationVApp (Pay as you go), a limit needs to be set
.PARAMETER StorageLimit
Storage Limit (MB) of the New Org VDC as String
.PARAMETER StorageProfile
Storage Profile of the New Org VDC as String
.PARAMETER NetworkPool
Network Pool of the New Org VDC as String
.PARAMETER ExternalNetwork
Optional External Network of the New Org VDC as String
.PARAMETER Enabled
Should the New Org VDC be enabled after creation
Default:$false
Note: If an External Network is requested the Org VDC will be enabled during External Network Configuration
.PARAMETER ProviderVDC
ProviderVDC where the new Org VDC should be created as string
.PARAMETER Org
Org where the new Org VDC should be created as string
.PARAMETER Timeout
Timeout for the Org VDC to get Ready
Default: 120s
#>
Param (
[Parameter(Mandatory=$True, ValueFromPipeline=$False, HelpMessage="Name of the New Org VDC as String")]
[ValidateNotNullorEmpty()]
[String] $Name,
[Parameter(Mandatory=$True, ValueFromPipeline=$False, HelpMessage="Allocation Model of the New Org VDC as String")]
[ValidateNotNullorEmpty()]
[ValidateSet("AllocationPool","AllocationVApp")]
[String] $AllocationModel,
[Parameter(Mandatory=$False, ValueFromPipeline=$False, HelpMessage="CPU Limit (MHz) of the New Org VDC as String")]
[ValidateNotNullorEmpty()]
[int] $CPULimit = 0,
[Parameter(Mandatory=$False, ValueFromPipeline=$False, HelpMessage="Memory Limit (MB) of the New Org VDC as String")]
[ValidateNotNullorEmpty()]
[int] $MEMLimit = 0,
[Parameter(Mandatory=$True, ValueFromPipeline=$False, HelpMessage="Storage Limit (MB) of the New Org VDC as String")]
[ValidateNotNullorEmpty()]
[int] $StorageLimit,
[Parameter(Mandatory=$True, ValueFromPipeline=$False, HelpMessage="Storage Profile of the New Org VDC as String")]
[ValidateNotNullorEmpty()]
[String] $StorageProfile,
[Parameter(Mandatory=$True, ValueFromPipeline=$False, HelpMessage="Network Pool of the New Org VDC as String")]
[ValidateNotNullorEmpty()]
[String] $NetworkPool,
[Parameter(Mandatory=$False, ValueFromPipeline=$False, HelpMessage="Optional External Network of the New Org VDC as String")]
[ValidateNotNullorEmpty()]
[String] $ExternalNetwork,
[Parameter(Mandatory=$False, ValueFromPipeline=$False, HelpMessage="Should the New Org VDC be enabled after creation")]
[ValidateNotNullorEmpty()]
[Switch]$Enabled,
[Parameter(Mandatory=$True, ValueFromPipeline=$False, HelpMessage="ProviderVDC where the new Org VDC should be created as string")]
[ValidateNotNullorEmpty()]
[String] $ProviderVDC,
[Parameter(Mandatory=$True, ValueFromPipeline=$False, HelpMessage="Org where the new Org VDC should be created as string")]
[ValidateNotNullorEmpty()]
[String] $Org,
[Parameter(Mandatory=$False, ValueFromPipeline=$False,HelpMessage="Timeout for the Org VDC to get Ready")]
[ValidateNotNullorEmpty()]
[int] $Timeout = 120
)
Process {
## Create Objects and all Settings
Write-Verbose "Create Objects and all Settings"
$adminVdc = New-Object VMware.VimAutomation.Cloud.Views.AdminVdc
$adminVdc.Name = $name
$adminVdc.IsEnabled = $Enabled
$OrgVdcproviderVdc = Get-ProviderVdc $ProviderVDC
$providerVdcRef = New-Object VMware.VimAutomation.Cloud.Views.Reference
$providerVdcRef.Href = $OrgVdcproviderVdc.Href
$adminVdc.ProviderVdcReference = $providerVdcRef
$adminVdc.AllocationModel = $AllocationModel
$adminVdc.ComputeCapacity = New-Object VMware.VimAutomation.Cloud.Views.ComputeCapacity
$adminVdc.ComputeCapacity.Cpu = New-Object VMware.VimAutomation.Cloud.Views.CapacityWithUsage
$adminVdc.ComputeCapacity.Cpu.Units = "MHz"
$adminVdc.ComputeCapacity.Cpu.Limit = $CPULimit
$adminVdc.ComputeCapacity.Cpu.Allocated = $CPULimit
$adminVdc.ComputeCapacity.Memory = New-Object VMware.VimAutomation.Cloud.Views.CapacityWithUsage
$adminVdc.ComputeCapacity.Memory.Units = "MB"
$adminVdc.ComputeCapacity.Memory.Limit = $MEMLimit
$adminVdc.ComputeCapacity.Memory.Allocated = $MEMLimit
$adminVdc.StorageCapacity = New-Object VMware.VimAutomation.Cloud.Views.CapacityWithUsage
$adminVdc.StorageCapacity.Units = "MB"
$adminVdc.StorageCapacity.Limit = $StorageLimit
$adminVdc.NetworkQuota = 10
$adminVdc.VmQuota = 0
$adminVdc.VCpuInMhz = 2000
$adminVdc.VCpuInMhz2 = 2000
$adminVdc.UsesFastProvisioning = $false
$adminVdc.IsThinProvision = $true
## Create Org vDC
Write-Verbose "Create Org vDC"
$OrgED = (Get-Org $Org).ExtensionData
$orgVdc = $orgED.CreateVdc($adminVdc)
## Wait for getting Ready
Write-Verbose "Wait for OrgVdc getting Ready after creation"
$i = 0
while(($orgVdc = Get-OrgVdc -Name $Name -Verbose:$false).Status -eq "NotReady"){
$i++
Start-Sleep 2
if($i -gt $Timeout) { Write-Error "Creating OrgVdc Failed."; break}
Write-Progress -Activity "Creating OrgVdc" -Status "Wait for OrgVdc to become Ready..."
}
Write-Progress -Activity "Creating OrgVdc" -Completed
Start-Sleep 2
## Search given Storage Profile
Write-Verbose "Search given Storage Profile"
$Filter = "ProviderVdc==" + $OrgVdcproviderVdc.Id
$ProVdcStorageProfile = search-cloud -QueryType ProviderVdcStorageProfile -Name $StorageProfile -Filter $Filter | Get-CIView
## Create Storage Profile Object with Settings
Write-Verbose "Create Storage Profile Object with Settings"
$spParams = new-object VMware.VimAutomation.Cloud.Views.VdcStorageProfileParams
$spParams.Limit = $StorageLimit
$spParams.Units = "MB"
$spParams.ProviderVdcStorageProfile = $ProVdcStorageProfile.href
$spParams.Enabled = $true
$spParams.Default = $true
$UpdateParams = new-object VMware.VimAutomation.Cloud.Views.UpdateVdcStorageProfiles
$UpdateParams.AddStorageProfile = $spParams
## Update Org vDC
$orgVdc = Get-OrgVdc -Name $name
$orgVdc.ExtensionData.CreateVdcStorageProfile($UpdateParams)
## Wait for getting Ready
Write-Verbose "Wait for OrgVdc getting Ready after update"
while(($orgVdc = Get-OrgVdc -Name $name -Verbose:$false).Status -eq "NotReady"){
$i++
Start-Sleep 1
if($i -gt $Timeout) { Write-Error "Update OrgVdc Failed."; break}
Write-Progress -Activity "Updating OrgVdc" -Status "Wait for OrgVdc to become Ready..."
}
Write-Progress -Activity "Updating OrgVdc" -Completed
Start-Sleep 1
## Search Any-StorageProfile
Write-Verbose "Search Any-StorageProfile"
$orgvDCAnyProfile = search-cloud -querytype AdminOrgVdcStorageProfile | Where-Object {($_.Name -match '\*') -and ($_.VdcName -eq $orgVdc.Name)} | Get-CIView
## Disable Any-StorageProfile
Write-Verbose "Disable Any-StorageProfile"
$orgvDCAnyProfile.Enabled = $False
$return = $orgvDCAnyProfile.UpdateServerData()
## Remove Any-StorageProfile
Write-Verbose "Remove Any-StorageProfile"
$ProfileUpdateParams = new-object VMware.VimAutomation.Cloud.Views.UpdateVdcStorageProfiles
$ProfileUpdateParams.RemoveStorageProfile = $orgvDCAnyProfile.href
$remove = $orgvdc.extensiondata.CreatevDCStorageProfile($ProfileUpdateParams)
## Wait for getting Ready
Write-Verbose "Wait for getting Ready"
while(($orgVdc = Get-OrgVdc -Name $name -Verbose:$false).Status -eq "NotReady"){
$i++
Start-Sleep 1
if($i -gt $Timeout) { Write-Error "Update Org Failed."; break}
Write-Progress -Activity "Updating Org" -Status "Wait for Org to become Ready..."
}
Write-Progress -Activity "Updating Org" -Completed
Start-Sleep 1
## Set NetworkPool for correct location
Write-Verbose "Set NetworkPool for correct location"
$orgVdc = Get-OrgVdc -Name $name
$ProVdcNetworkPool = Get-NetworkPool -ProviderVdc $ProviderVDC -Name $NetworkPool
$set = Set-OrgVdc -OrgVdc $orgVdc -NetworkPool $ProVdcNetworkPool -NetworkMaxCount "10"
## Create private Catalog
Write-Verbose "Create private Catalog Object"
$OrgCatalog = New-Object VMware.VimAutomation.Cloud.Views.AdminCatalog
$OrgCatalog.name = "$Org Private Catalog"
if (!(Get-Org $org | Get-Catalog -Name $OrgCatalog.name -ErrorAction SilentlyContinue)) {
Write-Verbose "Create private Catalog"
$CreateCatalog = (Get-Org $org | Get-CIView).CreateCatalog($OrgCatalog)
$AccessControlRule = New-CIAccessControlRule -Entity $CreateCatalog.name -EveryoneInOrg -AccessLevel ReadWrite -Confirm:$False
}
else {
Write-Output "Catalog '$($OrgCatalog.name)' aleady exists!"
}
## Create a direct connect network
if ($ExternalNetwork) {
Write-Verbose "Create a direct connect network"
Write-Output "Org VDC '$Name' needs to be enabled to add an external Network!"
$EnableOrgVdc = Set-OrgVdc -OrgVdc $Name -Enabled:$True
$orgVdcView = Get-OrgVdc $Name | Get-CIView
$extNetwork = $_.externalnetwork
$extNetwork = Get-ExternalNetwork | Get-CIView -Verbose:$false | Where-Object {$_.name -eq $ExternalNetwork}
$orgNetwork = new-object vmware.vimautomation.cloud.views.orgvdcnetwork
$orgNetwork.name = $ExternalNetwork
$orgNetwork.Configuration = New-Object VMware.VimAutomation.Cloud.Views.NetworkConfiguration
$orgNetwork.Configuration.FenceMode = 'bridged'
$orgNetwork.configuration.ParentNetwork = New-Object vmware.vimautomation.cloud.views.reference
$orgNetwork.configuration.ParentNetwork.href = $extNetwork.href
$result = $orgVdcView.CreateNetwork($orgNetwork)
}
Get-OrgVdc -Name $name | Format-Table -AutoSize
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 89 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 79 KiB

View File

@@ -0,0 +1,35 @@
$moduleRoot = Resolve-Path "$PSScriptRoot\.."
$moduleName = "VMware-vCD-Module"
$ConfigFile = "$moduleRoot\examples\OnBoarding.json"
Describe "General project validation: $moduleName" {
$scripts = Get-ChildItem $moduleRoot -Include *.ps1, *.psm1, *.psd1 -Recurse
# TestCases are splatted to the script so we need hashtables
$testCase = $scripts | Foreach-Object {@{file = $_}}
It "Script <file> should be valid powershell" -TestCases $testCase {
param($file)
$file.fullname | Should Exist
$contents = Get-Content -Path $file.fullname -ErrorAction Stop
$errors = $null
$null = [System.Management.Automation.PSParser]::Tokenize($contents, [ref]$errors)
$errors.Count | Should Be 0
}
It "Module '$moduleName' prerequirements are met" {
{Import-Module VMware.VimAutomation.Cloud -Force} | Should Not Throw
}
It "Module '$moduleName' can import cleanly" {
{Import-Module (Join-Path $moduleRoot "$moduleName.psd1") -force } | Should Not Throw
}
It "Module '$moduleName' JSON example is valid" {
{Get-Content -Raw -Path $ConfigFile | ConvertFrom-Json} | Should Not Throw
}
}

View File

@@ -0,0 +1,30 @@
VMware-vCD-TenantReport PowerShell Module
=============
# About
## Project Owner:
Markus Kraus [@vMarkus_K](https://twitter.com/vMarkus_K)
MY CLOUD-(R)EVOLUTION [mycloudrevolution.com](http://mycloudrevolution.com/)
## Project WebSite:
[mycloudrevolution.com](http://mycloudrevolution.com/)
## Project Documentation:
[Read the Docs](http://readthedocs.io/)
## Project Description:
The 'VMware-vCD-TenantReport' PowerShell Module creates with the Fuction 'Get-VcdTenantReport' a HTML Report of your vCloud Director Objects.
![Get-VcdTenantReport](/media/Get-VcdTenantReport.png)
Big thanks to [Timothy Dewin](https://twitter.com/tdewin) for his great [PowerStartHTML](https://github.com/tdewin/randomsamples/tree/master/powerstarthtml) PowerShell Module which is used to generate the Report for this Module.

View File

@@ -0,0 +1,122 @@
#
# Modulmanifest für das Modul "VMware-vCD-TenantReport"
#
# Generiert von: Markus Kraus
#
# Generiert am: 8/22/2017
#
@{
# Die diesem Manifest zugeordnete Skript- oder Binärmoduldatei.
# RootModule = 'VMware-vCD-TenantReport.psm1'
# Die Versionsnummer dieses Moduls
ModuleVersion = '1.0.2'
# ID zur eindeutigen Kennzeichnung dieses Moduls
GUID = '21a71eaa-d259-48c5-8482-643ba152af76'
# Autor dieses Moduls
Author = 'Markus'
# Unternehmen oder Hersteller dieses Moduls
CompanyName = 'mycloudrevolution.com'
# Urheberrechtserklärung für dieses Modul
Copyright = '(c) 2017 Markus Kraus. Alle Rechte vorbehalten.'
# Beschreibung der von diesem Modul bereitgestellten Funktionen
# Description = ''
# Die für dieses Modul mindestens erforderliche Version des Windows PowerShell-Moduls
# PowerShellVersion = ''
# Der Name des für dieses Modul erforderlichen Windows PowerShell-Hosts
# PowerShellHostName = ''
# Die für dieses Modul mindestens erforderliche Version des Windows PowerShell-Hosts
# PowerShellHostVersion = ''
# Die für dieses Modul mindestens erforderliche Microsoft .NET Framework-Version
# DotNetFrameworkVersion = ''
# Die für dieses Modul mindestens erforderliche Version der CLR (Common Language Runtime)
# CLRVersion = ''
# Die für dieses Modul erforderliche Prozessorarchitektur ("Keine", "X86", "Amd64").
# ProcessorArchitecture = ''
# Die Module, die vor dem Importieren dieses Moduls in die globale Umgebung geladen werden müssen
# RequiredModules = @()
# Die Assemblys, die vor dem Importieren dieses Moduls geladen werden müssen
# RequiredAssemblies = @()
# Die Skriptdateien (PS1-Dateien), die vor dem Importieren dieses Moduls in der Umgebung des Aufrufers ausgeführt werden.
# ScriptsToProcess = @()
# Die Typdateien (.ps1xml), die beim Importieren dieses Moduls geladen werden sollen
# TypesToProcess = @()
# Die Formatdateien (.ps1xml), die beim Importieren dieses Moduls geladen werden sollen
# FormatsToProcess = @()
# Die Module, die als geschachtelte Module des in "RootModule/ModuleToProcess" angegebenen Moduls importiert werden sollen.
NestedModules = @( "modules/PowerStartHTML/PowerStartHTML.psd1",
"functions/Get-VcdTenantReport.psm1" )
# Aus diesem Modul zu exportierende Funktionen
FunctionsToExport = '*'
# Aus diesem Modul zu exportierende Cmdlets
CmdletsToExport = '*'
# Die aus diesem Modul zu exportierenden Variablen
VariablesToExport = '*'
# Aus diesem Modul zu exportierende Aliase
AliasesToExport = '*'
# Aus diesem Modul zu exportierende DSC-Ressourcen
# DscResourcesToExport = @()
# Liste aller Module in diesem Modulpaket
# ModuleList = @()
# Liste aller Dateien in diesem Modulpaket
# FileList = @()
# Die privaten Daten, die an das in "RootModule/ModuleToProcess" angegebene Modul übergeben werden sollen. Diese können auch eine PSData-Hashtabelle mit zusätzlichen von PowerShell verwendeten Modulmetadaten enthalten.
PrivateData = @{
PSData = @{
# 'Tags' wurde auf das Modul angewendet und unterstützt die Modulermittlung in Onlinekatalogen.
# Tags = @()
# Eine URL zur Lizenz für dieses Modul.
# LicenseUri = ''
# Eine URL zur Hauptwebsite für dieses Projekt.
# ProjectUri = ''
# Eine URL zu einem Symbol, das das Modul darstellt.
# IconUri = ''
# 'ReleaseNotes' des Moduls
# ReleaseNotes = ''
} # Ende der PSData-Hashtabelle
} # Ende der PrivateData-Hashtabelle
# HelpInfo-URI dieses Moduls
# HelpInfoURI = ''
# Standardpräfix für Befehle, die aus diesem Modul exportiert werden. Das Standardpräfix kann mit "Import-Module -Prefix" überschrieben werden.
# DefaultCommandPrefix = ''
}

View File

@@ -0,0 +1,251 @@
function Get-VcdTenantReport {
<#
.NOTES
===========================================================================
Created by: Markus Kraus
Twitter: @VMarkus_K
Private Blog: mycloudrevolution.com
===========================================================================
Changelog:
1.0.0 - Inital Release
1.0.1 - Removed "Test-IP" Module
1.0.2 - More Detailed Console Log
===========================================================================
External Code Sources:
Examle Usage of BOOTSTRAP with PowerShell
https://github.com/tdewin/randomsamples/tree/master/powershell-veeamallstat
BOOTSTRAP with PowerShell
https://github.com/tdewin/randomsamples/tree/master/powerstarthtml
===========================================================================
Tested Against Environment:
vCD Version: 8.20
PowerCLI Version: PowerCLI 6.5.1
PowerShell Version: 5.0
OS Version: Windows 8.1
Keyword: VMware, vCD, Report, HTML
===========================================================================
.DESCRIPTION
This Function creates a HTML Report for your vCloud Director Organization.
This Function is fully tested as Organization Administrator.
With lower permissions a unexpected behavior is possible.
.Example
Get-VcdTenantReport -Server $ServerFQDN -Org $OrgName -Credential $MyCedential
.Example
Get-VcdTenantReport -Server $ServerFQDN -Org $OrgName -Path "C:\Temp\Report.html"
.PARAMETER Server
The FQDN of your vCloud Director Endpoint.
.PARAMETER Org
The Organization Name.
.PARAMETER Credential
PowerShell Credentials to access the Eénvironment.
.PARAMETER Path
The Path of the exported HTML Report.
#>
#Requires -Version 5
#Requires -Modules VMware.VimAutomation.Cloud, @{ModuleName="VMware.VimAutomation.Cloud";ModuleVersion="6.5.1.0"}
[CmdletBinding()]
param(
[Parameter(Mandatory=$True, ValueFromPipeline=$False)]
[ValidateNotNullorEmpty()]
[String] $Server,
[Parameter(Mandatory=$True, ValueFromPipeline=$False)]
[ValidateNotNullorEmpty()]
[String] $Org,
[Parameter(Mandatory=$False, ValueFromPipeline=$False)]
[ValidateNotNullorEmpty()]
[PSCredential] $Credential,
[Parameter(Mandatory=$false, ValueFromPipeline=$False)]
[ValidateNotNullorEmpty()]
[String] $Path = ".\Report.html"
)
Process {
# Start Connection to vCD
if ($global:DefaultCIServers) {
"$(Get-Date -Format "yyyy-MM-dd HH:mm:ss") - Disconnect existing vCD Server ..."
$Trash = Disconnect-CIServer -Server * -Force:$true -Confirm:$false -ErrorAction SilentlyContinue
}
"$(Get-Date -Format "yyyy-MM-dd HH:mm:ss") - Connect vCD Server ..."
if ($Credential) {
$Trash = Connect-CIServer -Server $Server -Org $Org -Credential $Credential -ErrorAction Stop
}
else {
$Trash = Connect-CIServer -Server $Server -Org $Org -ErrorAction Stop
}
"$(Get-Date -Format "yyyy-MM-dd HH:mm:ss") - Create HTML Report..."
# Init HTML Report
$ps = New-PowerStartHTML -title "vCD Tenant Report"
#Set CSS Style
$ps.cssStyles['.bgtitle'] = "background-color:grey"
$ps.cssStyles['.bgsubsection'] = "background-color:#eee;"
# Processing Data
## Get Main Objects
[Array] $OrgVdcs = Get-OrgVdc
[Array] $Catalogs = Get-Catalog
[Array] $Users = Get-CIUser
## Add Header to Report
$ps.Main().Add("div","jumbotron").N()
$ps.Append("h1","display-3",("vCD Tenant Report" -f $OrgVdcs.Count)).Append("p","lead","Organization User Count: {0}" -f $Users.Count).Append("p","lead","Organization Catalog Count: {0}" -f $Catalogs.Count).Append("p","lead","Organization VDC Count: {0}" -f $OrgVdcs.Count).Append("hr","my-4").Append("p","font-italic","This Report lists the most important objects in your vCD Environmet. For more details contact your Service Provider").N()
## add Org Users to Report
$ps.Main().Append("h2",$null,"Org Users").N()
$ps.Add('table','table').Add("tr","bgtitle text-white").Append("th",$null,"User Name").Append("th",$null,"Locked").Append("th",$null,"DeployedVMCount").Append("th",$null,"StoredVMCount").N()
$ps.Add("tr").N()
foreach ($User in $Users) {
$ps.Append("td",$null,$User.Name).N()
$ps.Append("td",$null,$User.Locked).N()
$ps.Append("td",$null,$User.DeployedVMCount).N()
$ps.Append("td",$null,$User.StoredVMCount).N()
$ps.Up().N()
}
$ps.Up().N()
## add Org Catalogs to Report
$ps.Main().Append("h2",$null,"Org Catalogs").N()
foreach ($Catalog in $Catalogs) {
$ps.Add('table','table').Add("tr","bgtitle text-white").Append("th",$null,"Catalog Name").N()
$ps.Add("tr").N()
$ps.Append("td",$null,$Catalog.Name).Up().N()
$ps.Add("td","bgsubsection").N()
$ps.Add("table","table bgcolorsub").N()
$ps.Add("tr").N()
$headers = @("Item")
foreach ($h in $headers) {
$ps.Append("th",$null,$h).N()
}
$ps.Up().N()
### add Itens of the Catalog to the Report
[Array] $Items = $Catalog.ExtensionData.CatalogItems.CatalogItem
foreach ($Item in $Items) {
$ps.Add("tr").N()
$ps.Append("td",$null,$Item.Name).N()
$ps.Up().N()
}
$ps.Up().Up().N()
}
$ps.Up().N()
## add Org VDC`s to the Report
$ps.Main().Append("h2",$null,"Org VDCs").N()
foreach ($OrgVdc in $OrgVdcs) {
$ps.Main().Add('table','table table-striped table-inverse').Add("tr").Append("th",$null,"VDC Name").Append("th",$null,"Enabled").Append("th",$null,"CpuUsedGHz").Append("th",$null,"MemoryUsedGB").Append("th",$null,"StorageUsedGB").Up().N()
$ps.Add("tr").N()
$ps.Append("td",$null,$OrgVdc.Name).Append("td",$null,$OrgVdc.Enabled).Append("td",$null,$OrgVdc.CpuUsedGHz).Append("td",$null,$OrgVdc.MemoryUsedGB).Append("td",$null,[Math]::Round($OrgVdc.StorageUsedGB,2)).Up().N()
### add Edge Gateways of this Org VDC to Report
$ps.Main().Append("h3",$null,"Org VDC Edge Gateways").N()
[Array] $Edges = Search-Cloud -QueryType EdgeGateway -Filter "Vdc==$($OrgVdc.Id)"
foreach ($Edge in $Edges) {
$ps.Add('table','table').Add("tr","bgtitle text-white").Append("th",$null,"Edge Name").N()
$ps.Add("tr").N()
$ps.Append("td",$null,$Edge.Name).Up().N()
$ps.Add("td","bgsubsection").N()
$ps.Add("table","table bgcolorsub").N()
$ps.Append("tr").Append("td","font-weight-bold","HaStatus").Append("td",$null,($Edge.HaStatus)).N()
$ps.Append("td","font-weight-bold","AdvancedNetworkingEnabled").Append("td",$null,$Edge.AdvancedNetworkingEnabled).N()
$ps.Append("tr").Append("td","font-weight-bold","NumberOfExtNetworks").Append("td",$null,($Edge.NumberOfExtNetworks)).N()
$ps.Append("td","font-weight-bold","NumberOfOrgNetworks").Append("td",$null,$Edge.NumberOfOrgNetworks).N()
$ps.Up().Up().N()
}
$ps.Up().N()
### add Org Networks of this Org VDC to Report
$ps.Main().Append("h3",$null,"Org VDC Networks").N()
[Array] $Networks = $OrgVdc | Get-OrgVdcNetwork
foreach ($Network in $Networks) {
$ps.Add('table','table').Add("tr","bgtitle text-white").Append("th",$null,"Network Name").N()
$ps.Add("tr").N()
$ps.Append("td",$null,$Network.Name).Up().N()
$ps.Add("td","bgsubsection").N()
$ps.Add("table","table bgcolorsub").N()
$ps.Append("tr").Append("td","font-weight-bold","DefaultGateway").Append("td",$null,($Network.DefaultGateway)).N()
$ps.Append("td","font-weight-bold","Netmask").Append("td",$null,$Network.Netmask).N()
$ps.Append("tr").Append("td","font-weight-bold","NetworkType").Append("td",$null,($Network.NetworkType)).N()
$ps.Append("td","font-weight-bold","StaticIPPool").Append("td",$null,$Network.StaticIPPool).N()
$ps.Up().Up().N()
}
$ps.Up().N()
### add vApps of this Org VDC to Report
$ps.Main().Append("h3",$null,"Org VDC vApps").N()
[Array] $Vapps = $OrgVdc | Get-CIVApp
foreach ($Vapp in $Vapps) {
$ps.Add('table','table').Add("tr","bgtitle text-white").Append("th",$null,"vApp Name").Append("th",$null,"Owner").Up().N()
$ps.Add("tr").N()
$ps.Append("td",$null,$Vapp.Name).Append("td",$null,$Vapp.Owner).Up().N()
#### add VMs of this vApp to Report
$ps.Add("td","bgsubsection").N()
$ps.Add("table","table bgcolorsub").N()
$ps.Add("tr").N()
$headers = @("Name","Status","GuestOSFullName","CpuCount","MemoryGB")
foreach ($h in $headers) {
$ps.Append("th",$null,$h).N()
}
$ps.Up().N()
[Array] $VMs = $Vapp | Get-CIVM
foreach ($VM in $VMs) {
$ps.Add("tr").N()
$ps.Append("td",$null,$VM.Name).N()
$ps.Append("td",$null,$VM.Status).N()
$ps.Append("td",$null,$VM.GuestOSFullName).N()
$ps.Append("td",$null,$VM.CpuCount).N()
$ps.Append("td",$null,$VM.MemoryGB).N()
$ps.Up().N()
}
$ps.Up().Up().N()
}
$ps.Up().N()
}
$ps.save($Path)
"$(Get-Date -Format "yyyy-MM-dd HH:mm:ss") - Open HTML Report..."
Start-Process $Path
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.1 KiB

View File

@@ -0,0 +1,237 @@
class PowerStartHTML {
[string]$PowerStartHtmlTemplate = "<html><head><meta charset=`"UTF-8`"/><title></title><style></style></head><body><div/></body></html>"
[xml]$xmlDocument = $null
$onLoadJS = $null
$cssStyles= @{}
$lastEl = $null
$newEl = $null
$indentedOutput = $false
$bootstrapAtCompile = $false
PowerStartHTML([string]$title) {
$this.xmlDocument = $this.PowerStartHtmlTemplate
$this.xmlDocument.html.head.title = $title
$this.lastEl = $this.xmlDocument.html.body.ChildNodes[0]
$this.onLoadJS = New-Object System.Collections.Generic.List[System.String]
}
[string] GetHtml() {
$xmlclone = $this.xmlDocument.Clone()
$csb = [System.Text.StringBuilder]::new()
foreach ($cssStyle in $this.cssStyles.GetEnumerator()) {
$null = $csb.AppendFormat("{0} {{ {1} }}",$cssStyle.Name,$cssStyle.Value)
}
$this.xmlDocument.html.head.style = $csb.toString()
$this.AddBootStrapAtCompile()
if($this.onLoadJS.Count -gt 0) {
$this.onLoadJs.Insert(0,"`r`n`$(document).ready(function() {")
$this.onLoadJs.Add("})`r`n")
$el = $this.xmlDocument.CreateElement("script")
$el.AppendChild($this.xmlDocument.CreateTextNode([System.String]::Join("`r`n",$this.onLoadJs)))
$this.xmlDocument.html.body.AppendChild($el)
}
$ms = [System.IO.MemoryStream]::new()
$xmlWriter = [System.Xml.XmlTextWriter]::new($ms,[System.Text.Encoding]::UTF8)
if($this.indentedOutput) {
$xmlWriter.Formatting = [System.Xml.Formatting]::Indented
}
$this.xmlDocument.WriteContentTo($xmlWriter)
$xmlWriter.Flush()
$ms.Flush()
#make sure that everytime we do gethtml we keep it clean
$this.xmlDocument = $xmlclone
$ms.Position = 0;
$sr = [System.IO.StreamReader]::new($ms);
return ("<!DOCTYPE html>{0}`r`n" -f $sr.ReadToEnd())
}
Save($path) {
$this.GetHtml() | Set-Content -path $path -Encoding UTF8
}
AddAttr($el,$name,$value) {
$attr = $this.xmlDocument.CreateAttribute($name)
$attr.Value = $value
$el.Attributes.Append($attr)
}
AddAttrs($el,$dict) {
foreach($a in $dict.GetEnumerator()) {
$this.AddAttr($el,$a.Name,$a.Value)
}
}
[PowerStartHTML] AddBootStrap() {
$this.bootstrapAtCompile = $true
return $this
}
AddJSScript($href,$integrity) {
$el = $this.xmlDocument.CreateElement("script")
$attrs = @{
"src"="$href";
"integrity"="$integrity";
"crossorigin"="anonymous"
}
$this.AddAttrs($el,$attrs)
$el.AppendChild($this.xmlDocument.CreateTextNode(""))
$this.xmlDocument.html.body.AppendChild($el)
}
AddBootStrapAtCompile() { #Bootstrap script needs to be added at the end
if($this.bootstrapAtCompile) {
$el = $this.xmlDocument.CreateElement("link")
$attrs = @{
"rel"="stylesheet";
"href"='https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-beta/css/bootstrap.min.css';
"integrity"="sha384-/Y6pD6FV/Vv2HJnA6t+vslU6fwYXjCFtcEpHbNJ0lyAFsXTsjBbfaDjzALeQsN6M";
"crossorigin"="anonymous"
}
$this.AddAttrs($el,$attrs)
$el.AppendChild($this.xmlDocument.CreateTextNode(""))
$this.xmlDocument.html.head.AppendChild($el)
$this.AddJSScript('https://code.jquery.com/jquery-3.2.1.slim.min.js',"sha384-KJ3o2DKtIkvYIK3UENzmM7KCkRr/rE9/Qpg6aAZGJwFDMVNA/GpGFF93hXpG5KkN")
$this.AddJSScript('https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.11.0/umd/popper.min.js',"sha384-b/U6ypiBEHpOf/4+1nzFpr53nxSS+GLCkfwBdFNTxtclqqenISfwAzpKaMNFNmj4")
$this.AddJSScript('https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-beta/js/bootstrap.min.js',"sha384-h0AbiXch4ZDo7tp9hKZ4TsHbi047NrKGLO3SEJAg45jXxnGIfYzk4Si90RDIqNm1")
}
}
[PowerStartHTML] AddContainerAttrToMain() {
$this.AddAttr($this.xmlDocument.html.body.ChildNodes[0],"class","container")
return $this
}
[PowerStartHTML] Append($elType = "table",$className=$null,[string]$text=$null) {
$el = $this.xmlDocument.CreateElement($elType)
if($text -ne $null) {
$el.AppendChild($this.xmlDocument.CreateTextNode($text))
}
if($className -ne $null) {
$this.AddAttr($el,"class",$className)
}
$this.lastEl.AppendChild($el)
$this.newEl = $el
return $this
}
[PowerStartHTML] Append($elType = "table",$className=$null) { return $this.Append($elType,$className,$null) }
[PowerStartHTML] Append($elType = "table") { return $this.Append($elType,$null,$null) }
[PowerStartHTML] Add($elType = "table",$className=$null,[string]$text=$null) {
$this.Append($elType,$className,$text)
$this.lastEl = $this.newEl
return $this
}
[PowerStartHTML] Add($elType = "table",$className=$null) { return $this.Add($elType,$className,$null) }
[PowerStartHTML] Add($elType = "table") { return $this.Add($elType,$null,$null) }
[PowerStartHTML] Main() {
$this.lastEl = $this.xmlDocument.html.body.ChildNodes[0];
return $this
}
[PowerStartHTML] Up() {
$this.lastEl = $this.lastEl.ParentNode;
return $this
}
N() {}
}
class PowerStartHTMLPassThroughLine {
$object;$cells
PowerStartHTMLPassThroughLine($object) {
$this.object = $object;
$this.cells = new-object System.Collections.HashTable;
}
}
class PowerStartHTMLPassThroughElement {
$name;$text;$element;$id
PowerStartHTMLPassThroughElement($name,$text,$element,$id) {
$this.name = $name; $this.text = $text; $this.element = $element;$this.id = $id
}
}
function New-PowerStartHTML {
param(
[Parameter(Mandatory=$true)][string]$title,
[switch]$nobootstrap=$false
)
$pshtml = (new-object PowerStartHTML($title))
if(-not $nobootstrap) {
$pshtml.AddBootStrap().AddContainerAttrToMain().N()
}
return $pshtml
}
function Add-PowerStartHTMLTable {
param(
[Parameter(Mandatory=$True,ValueFromPipeline=$True)]$object,
[PowerStartHTML]$psHtml,
[string]$tableTitle = $null,
[string]$tableClass = $null,
[string]$idOverride = $(if($tableTitle -ne $null) {($tableTitle.toLower() -replace "[^a-z0-9]","-") }),
[switch]$passthroughTable = $false,
[switch]$noheaders = $false
)
begin {
if($tableTitle -ne $null) {
$psHtml.Main().Append("h1",$null,$tableTitle).N()
if($idOverride -ne $null) {
$psHtml.AddAttr($psHtml.newEl,"id","header-$idOverride")
}
}
$psHtml.Main().Add("table").N()
[int]$r = 0
[int]$c = 0
if($idOverride -ne $null) {
$psHtml.AddAttr($psHtml.newEl,"id","table-$idOverride")
}
if($tableClass -ne $null) {
$psHtml.AddAttr($psHtml.newEl,"class",$tableClass)
}
[bool]$isFirst = $true
}
process {
$c = 0
$props = $object | Get-Member -Type Properties
if(-not $noheaders -and $isFirst) {
$psHtml.Add("tr").N()
if($idOverride -ne $null) {
$psHtml.AddAttr($psHtml.newEl,"id","table-$idOverride-trh")
}
$props | % {
$n = $_.Name;
$psHtml.Append("th",$null,$n).N()
if($idOverride -ne $null) {
$cellid = "table-$idOverride-td-$r-$c"
$psHtml.AddAttr($psHtml.newEl,"id",$cellid)
}
$c++
}
$c = 0
$psHtml.Up().N()
}
$psHtml.Add("tr").N()
if($idOverride -ne $null) {
$psHtml.AddAttr($psHtml.newEl,"id","table-$idOverride-tr-$r")
}
$pstableln = [PowerStartHTMLPassThroughLine]::new($object)
$props | % {
$n = $_.Name;
$psHtml.Append("td",$null,$object."$n").N()
$cellid = $null
if($idOverride -ne $null) {
$cellid = "table-$idOverride-td-$r-$c"
$psHtml.AddAttr($psHtml.newEl,"id",$cellid)
}
if($passthroughTable) {
$pstableln.cells.Add($n,[PowerStartHTMLPassThroughElement]::new($n,($object."$n"),$psHtml.newEl,$cellid))
}
$c++
}
if($passthroughTable) {
$pstableln
}
$psHtml.Up().N()
$isFirst = $false
$r++
}
end {
}
}
Export-ModuleMember -Function @('New-PowerStartHTML','Add-PowerStartHTMLTable')

View File

@@ -0,0 +1,24 @@
$moduleRoot = Resolve-Path "$PSScriptRoot\.."
$moduleName = "VMware-vCD-TenantReport"
Describe "General project validation: $moduleName" {
$scripts = Get-ChildItem $moduleRoot -Include *.ps1, *.psm1, *.psd1 -Recurse
# TestCases are splatted to the script so we need hashtables
$testCase = $scripts | Foreach-Object {@{file = $_}}
It "Script <file> should be valid powershell" -TestCases $testCase {
param($file)
$file.fullname | Should Exist
$contents = Get-Content -Path $file.fullname -ErrorAction Stop
$errors = $null
$null = [System.Management.Automation.PSParser]::Tokenize($contents, [ref]$errors)
$errors.Count | Should Be 0
}
It "Module '$moduleName' can import cleanly" {
{Import-Module (Join-Path $moduleRoot "$moduleName.psd1") -force } | Should Not Throw
}
}

View File

@@ -0,0 +1,54 @@
Function Get-CSPAccessToken {
<#
.NOTES
===========================================================================
Created by: William Lam
Date: 07/23/2018
Organization: VMware
Blog: https://www.virtuallyghetto.com
Twitter: @lamw
===========================================================================
.DESCRIPTION
Converts a Refresh Token from the VMware Console Services Portal
to CSP Access Token to access CSP API
.PARAMETER RefreshToken
The Refresh Token from the VMware Console Services Portal
.EXAMPLE
Get-CSPAccessToken -RefreshToken $RefreshToken
#>
Param (
[Parameter(Mandatory=$true)][String]$RefreshToken
)
$results = Invoke-WebRequest -Uri "https://console.cloud.vmware.com/csp/gateway/am/api/auth/api-tokens/authorize?refresh_token=$RefreshToken" -Method POST -ContentType "application/json" -UseBasicParsing -Headers @{"csp-auth-token"="$RefreshToken"}
if($results.StatusCode -ne 200) {
Write-Host -ForegroundColor Red "Failed to retrieve Access Token, please ensure your VMC Refresh Token is valid and try again"
break
}
$accessToken = ($results | ConvertFrom-Json).access_token
Write-Host "CSP Auth Token has been successfully retrieved and saved to `$env:cspAuthToken"
$env:cspAuthToken = $accessToken
}
Function Get-CSPServices {
<#
.NOTES
===========================================================================
Created by: William Lam
Date: 07/23/2018
Organization: VMware
Blog: https://www.virtuallyghetto.com
Twitter: @lamw
===========================================================================
.DESCRIPTION
Returns the list of CSP Services avialable for given user
.EXAMPLE
Get-CSPServices
#>
If (-Not $env:cspAuthToken) { Write-error "CSP Auth Token not found, please run Get-CSPAccessToken" } Else {
$results = Invoke-WebRequest -Uri "https://console.cloud.vmware.com/csp/gateway/slc/api/definitions?expand=1" -Method GET -ContentType "application/json" -UseBasicParsing -Headers @{"csp-auth-token"="$env:cspAuthToken"}
((($results.Content) | ConvertFrom-Json).results | where {$_.visible -eq $true}).displayName
}
}

View File

@@ -0,0 +1,88 @@
#
# Module manifest for module 'VMware.HCX'
#
# Generated by: wlam@vmware.com
#
# Generated on: 09/11/18
#
@{
# Script module or binary module file associated with this manifest.
RootModule = 'VMware.HCX.psm1'
# Version number of this module.
ModuleVersion = '1.0.2'
# Supported PSEditions
# CompatiblePSEditions = @()
# ID used to uniquely identify this module
GUID = '88898ed6-26e8-4dfa-a9de-10d3a12571de'
# Author of this module
Author = 'William Lam'
# Company or vendor of this module
CompanyName = 'VMware'
# Copyright statement for this module
Copyright = '(c) 2018 VMware. All rights reserved.'
# Description of the functionality provided by this module
Description = 'PowerShell Module for Managing Hybrid Cloud Extension (HCX) on VMware Cloud on AWS'
# Minimum version of the Windows PowerShell engine required by this module
PowerShellVersion = '6.0'
# Functions to export from this module, for best performance, do not use wildcards and do not delete the entry, use an empty array if there are no functions to export.
FunctionsToExport = 'Connect-HcxServer', 'Get-HcxCloudConfig', 'Get-HcxEndpoint', 'New-HcxMigration', 'Get-HcxMigration', 'Connect-HcxVAMI', 'Get-HcxVCConfig', 'Set-HcxLicense', 'Set-HcxVCConfig', 'Get-HcxNSXConfig', 'Set-HcxNSXConfig', 'Get-HcxCity', 'Get-HcxLocation', 'Set-HcxLocation', 'Get-HcxRoleMapping', 'Set-HcxRoleMapping', 'Get-HcxProxy', 'Set-HcxProxy', 'Remove-HcxProxy'
# Cmdlets to export from this module, for best performance, do not use wildcards and do not delete the entry, use an empty array if there are no cmdlets to export.
CmdletsToExport = @()
# Variables to export from this module
VariablesToExport = '*'
# Aliases to export from this module, for best performance, do not use wildcards and do not delete the entry, use an empty array if there are no aliases to export.
AliasesToExport = @()
# DSC resources to export from this module
# DscResourcesToExport = @()
# List of all modules packaged with this module
# ModuleList = @()
# List of all files packaged with this module
# FileList = @()
# Private data to pass to the module specified in RootModule/ModuleToProcess. This may also contain a PSData hashtable with additional module metadata used by PowerShell.
PrivateData = @{
PSData = @{
# Tags applied to this module. These help with module discovery in online galleries.
# Tags = @()
# A URL to the license for this module.
# LicenseUri = ''
# A URL to the main website for this project.
# ProjectUri = ''
# A URL to an icon representing this module.
# IconUri = ''
# ReleaseNotes of this module
# ReleaseNotes = ''
} # End of PSData hashtable
} # End of PrivateData hashtable
# HelpInfo URI of this module
# HelpInfoURI = ''
# Default prefix for commands exported from this module. Override the default prefix using Import-Module -Prefix.
# DefaultCommandPrefix = ''
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,18 @@
@{
ModuleToProcess = 'VMware.Hosted.psm1'
ModuleVersion = '1.0.0.0'
GUID = '11393D09-D6B8-4E79-B9BC-247F1BE66683'
Author = 'William Lam'
CompanyName = 'primp-industries.com'
Copyright = '(c) 2017. All rights reserved.'
Description = 'Powershell Module for VMware Fusion 10 REST API'
PowerShellVersion = '5.0'
FunctionsToExport = 'Get-HostedCommand','Connect-HostedServer','Disconnect-HostedServer','Get-HostedVM','Start-HostedVM','Stop-HostedVM','Suspend-HostedVM','Resume-HostedVM','New-HostedVM','Remove-HostedVM','Get-HostedVMSharedFolder','New-HostedVMSharedFolder','Remove-HostedVMSharedFolder','Get-HostedVMNic','Get-HostedNetworks'
PrivateData = @{
PSData = @{
Tags = @('Fusion','REST','vmrest')
LicenseUri = 'https://www.tldrlegal.com/l/mit'
ProjectUri = 'https://github.com/lamw/PowerCLI-Example-Scripts/tree/master/Modules/VMware.Hosted'
}
}
}

View File

@@ -0,0 +1,501 @@
Function Get-Confirmation {
$choice = ""
while ($choice -notmatch "[y|n]"){
$choice = read-host "Do you want to continue? (Y/N)"
}
if($choice -ne 'y') {
break
}
}
Function Connect-HostedServer {
Param (
[parameter(Mandatory=$true,ValueFromPipeline=$true)][string]$Server,
[parameter(Mandatory=$true,ValueFromPipeline=$true)][string]$Username,
[parameter(Mandatory=$true,ValueFromPipeline=$true)][string]$Password,
[parameter(Mandatory=$false,ValueFromPipeline=$true)][string]$Protocol = "http",
[parameter(Mandatory=$false,ValueFromPipeline=$true)][int]$Port = 8697
)
$pair = $Username+":"+$Password
$bytes = [System.Text.Encoding]::ASCII.GetBytes($pair)
$base64 = [System.Convert]::ToBase64String($bytes)
$basicAuthValue = "Basic $base64"
$headers = @{Authorization = $basicAuthValue}
$Global:DefaultHostedServer = [pscustomobject] @{
Server=$Protocol + "://" + $server + ":$Port/api";
Protcol=$Protocol
Headers=$headers
}
if($DefaultHostedServer.Protcol -eq "https") {
# PowerShell Core has a nice -SkipCertificateCheck but looks like Windows does NOT :(
if($PSVersionTable.PSEdition -eq "Core") {
$Global:fusionCommand = "Invoke-Webrequest -SkipCertificateCheck "
} else {
# Needed for Windows PowerShell to handle HTTPS scenario
# https://stackoverflow.com/a/15627483
$Provider = New-Object Microsoft.CSharp.CSharpCodeProvider
$Compiler = $Provider.CreateCompiler()
$Params = New-Object System.CodeDom.Compiler.CompilerParameters
$Params.GenerateExecutable = $false
$Params.GenerateInMemory = $true
$Params.IncludeDebugInformation = $false
$Params.ReferencedAssemblies.Add("System.DLL") > $null
$TASource=@'
namespace Local.ToolkitExtensions.Net.CertificatePolicy
{
public class TrustAll : System.Net.ICertificatePolicy
{
public bool CheckValidationResult(System.Net.ServicePoint sp,System.Security.Cryptography.X509Certificates.X509Certificate cert, System.Net.WebRequest req, int problem)
{
return true;
}
}
}
'@
$TAResults=$Provider.CompileAssemblyFromSource($Params,$TASource)
$TAAssembly=$TAResults.CompiledAssembly
## We create an instance of TrustAll and attach it to the ServicePointManager
$TrustAll = $TAAssembly.CreateInstance("Local.ToolkitExtensions.Net.CertificatePolicy.TrustAll")
[System.Net.ServicePointManager]::CertificatePolicy = $TrustAll
$Global:fusionCommand = "Invoke-Webrequest "
}
} else {
$Global:fusionCommand = "Invoke-Webrequest "
}
$Global:DefaultHostedServer
}
Function Disconnect-HostedServer {
Param (
[parameter(Mandatory=$true,ValueFromPipeline=$true)][string]$Server
)
$Global:DefaultHostedServer = $null
}
Function Get-HostedVM {
Param (
[parameter(Mandatory=$false,ValueFromPipeline=$true)][string]$Id
)
if(!$Global:DefaultHostedServer) {
Write-Host -ForegroundColor Red "You are not connected to Hosted Server, please run Connect-HostedServer"
exit
}
if($Id) {
$vmUri = $Global:DefaultHostedServer.Server + "/vms/" + $Id
try {
$params = "-Headers `$Global:DefaultHostedServer.Headers -Uri $vmUri -Method GET -ContentType `"application/vnd.vmware.vmw.rest-v1+json`""
$command = $Global:fusionCommand + $params
$vm = Invoke-Expression -Command $command | ConvertFrom-Json -ErrorAction Stop
} catch {
Write-host -ForegroundColor Red "Invalid VM Id $Id"
break
}
$vmIPUri = $Global:DefaultHostedServer.Server + "/vms/" + $Id + "/ip"
try {
$params = "-UseBasicParsing -Headers `$Global:DefaultHostedServer.Headers -Uri $vmIPUri -Method GET -ContentType `"application/vnd.vmware.vmw.rest-v1+json`""
$command = $Global:fusionCommand + $params
$vmIPResults = Invoke-Expression -Command $command | ConvertFrom-Json -ErrorAction Stop
$vmIP = $vmIPResults.ip
} catch {
$vmIP = "N/A"
}
$vmPowerUri = $Global:DefaultHostedServer.Server + "/vms/" + $Id + "/power"
try {
$params = "-UseBasicParsing -Headers `$Global:DefaultHostedServer.Headers -Uri $vmPowerUri -Method GET -ContentType `"application/vnd.vmware.vmw.rest-v1+json`""
$command = $Global:fusionCommand + $params
$vmPower = Invoke-Expression -Command $command | ConvertFrom-Json -ErrorAction Stop
} catch {
$vmPower = "N/A"
}
$results = [pscustomobject] @{
Id = $vm.Id;
CPU = $vm.Cpu.processors;
Memory = $vm.Memory;
PowerState = $vmPower.power_state;
IPAddress = $vmIP;
}
$results
} else {
$uri = $Global:DefaultHostedServer.Server + "/vms"
$params = "-UseBasicParsing -Headers `$Global:DefaultHostedServer.Headers -Uri $uri -Method GET -ContentType `"application/vnd.vmware.vmw.rest-v1+json`""
$command = $Global:fusionCommand + $params
try {
Invoke-Expression -Command $command | ConvertFrom-Json -ErrorAction Stop
} catch {
Write-host -ForegroundColor Red "Failed to list VMs"
}
}
}
Function Start-HostedVM {
Param (
[parameter(Mandatory=$true,ValueFromPipeline=$true)][string]$Id
)
if(!$Global:DefaultHostedServer) {
Write-Host -ForegroundColor Red "You are not connected to Hosted Server, please run Connect-HostedServer"
exit
}
$vmPowerUri = $Global:DefaultHostedServer.Server + "/vms/" + $Id + "/power"
try {
$params = "-UseBasicParsing -Headers `$Global:DefaultHostedServer.Headers -Uri $vmPowerUri -Method GET -ContentType `"application/vnd.vmware.vmw.rest-v1+json`""
$command = $Global:fusionCommand + $params
$vmPower = Invoke-Expression -Command $command | ConvertFrom-Json -ErrorAction Stop
} catch {
Write-host -ForegroundColor Red "Invalid VM Id $Id"
break
}
if($vmPower.power_state -eq "poweredOff" -or $vmPower.power_state -eq "suspended") {
try {
Write-Host "Powering on VM $Id ..."
$params = "-UseBasicParsing -Headers `$Global:DefaultHostedServer.Headers -Uri $vmPowerUri -Method PUT -ContentType `"application/vnd.vmware.vmw.rest-v1+json`" -Body `"on`""
$command = $Global:fusionCommand + $params
$vm = Invoke-Expression -Command $command | ConvertFrom-Json -ErrorAction Stop
} catch {
Write-host -ForegroundColor Red "Unable to Power On VM $Id"
break
}
} else {
Write-Host "VM $Id is already Powered On"
}
}
Function Stop-HostedVM {
Param (
[parameter(Mandatory=$true,ValueFromPipeline=$true)][string]$Id,
[parameter(Mandatory=$false,ValueFromPipeline=$true)][boolean]$Soft,
[parameter(Mandatory=$false,ValueFromPipeline=$true)][boolean]$Confirm = $true
)
if(!$Global:DefaultHostedServer) {
Write-Host -ForegroundColor Red "You are not connected to Hosted Server, please run Connect-HostedServer"
exit
}
if($Confirm) {
Get-Confirmation
}
$vmPowerUri = $Global:DefaultHostedServer.Server + "/vms/" + $Id + "/power"
try {
$params += "-UseBasicParsing -Headers `$Global:DefaultHostedServer.Headers -Uri $vmPowerUri -Method GET -ContentType `"application/vnd.vmware.vmw.rest-v1+json`""
$command = $Global:fusionCommand + $params
$vmPower = Invoke-Expression -Command $command | ConvertFrom-Json -ErrorAction Stop
} catch {
Write-host -ForegroundColor Red "Invalid VM Id $Id"
break
}
if($vmPower.power_state -eq "poweredOn") {
if($Soft) {
try {
Write-Host "Shutting down VM $Id ..."
$params = "-UseBasicParsing -Headers `$Global:DefaultHostedServer.Headers -Uri $vmPowerUri -Method PUT -ContentType `"application/vnd.vmware.vmw.rest-v1+json`" -Body `"shutdown`""
$command = $Global:fusionCommand + $params
$vm = Invoke-Expression -Command $command | ConvertFrom-Json -ErrorAction Stop
} catch {
Write-host -ForegroundColor Red "Unable to Shutdown VM $Id"
break
}
} else {
try {
Write-Host "Powering off VM $Id ..."
$params = "-UseBasicParsing -Headers `$Global:DefaultHostedServer.Headers -Uri $vmPowerUri -Method PUT -ContentType `"application/vnd.vmware.vmw.rest-v1+json`" -Body `"off`""
$command = $Global:fusionCommand + $params
$vm = Invoke-Expression -Command $command | ConvertFrom-Json -ErrorAction Stop
} catch {
Write-host -ForegroundColor Red "Unable to Power Off VM $Id"
break
}
}
} else {
Write-Host "VM $Id is already Powered Off"
}
}
Function Suspend-HostedVM {
Param (
[parameter(Mandatory=$true,ValueFromPipeline=$true)][string]$Id,
[parameter(Mandatory=$false,ValueFromPipeline=$true)][boolean]$Confirm
)
if(!$Global:DefaultHostedServer) {
Write-Host -ForegroundColor Red "You are not connected to Hosted Server, please run Connect-HostedServer"
exit
}
if($Confirm) {
Get-Confirmation
}
$vmPowerUri = $Global:DefaultHostedServer.Server + "/vms/" + $Id + "/power"
try {
$params = "-UseBasicParsing -Headers `$Global:DefaultHostedServer.Headers -Uri $vmPowerUri -Method GET -ContentType `"application/vnd.vmware.vmw.rest-v1+json`""
$command = $Global:fusionCommand + $params
$vmPower = Invoke-Expression -Command $command | ConvertFrom-Json -ErrorAction Stop
} catch {
Write-host -ForegroundColor Red "Invalid VM Id $Id"
break
}
if($vmPower.power_state -eq "poweredOn") {
try {
Write-Host "Suspending VM $Id ..."
$params = "-UseBasicParsing -Headers `$Global:DefaultHostedServer.Headers -Uri $vmPowerUri -Method PUT -ContentType `"application/vnd.vmware.vmw.rest-v1+json`" -Body `"suspend`""
$command = $Global:fusionCommand + $params
$vm = Invoke-Expression -Command $command | ConvertFrom-Json -ErrorAction Stop
} catch {
Write-host -ForegroundColor Red "Unable to suspend VM $Id"
break
}
} else {
Write-Host "VM $Id can not be suspended because it is either Powered Off or Suspended"
}
}
Function Resume-HostedVM {
Param (
[parameter(Mandatory=$true,ValueFromPipeline=$true)][string]$Id
)
if(!$Global:DefaultHostedServer) {
Write-Host -ForegroundColor Red "You are not connected to Hosted Server, please run Connect-HostedServer"
exit
}
$vmPowerUri = $Global:DefaultHostedServer.Server + "/vms/" + $Id + "/power"
try {
$params = "-UseBasicParsing -Headers `$Global:DefaultHostedServer.Headers -Uri $vmPowerUri -Method GET -ContentType `"application/vnd.vmware.vmw.rest-v1+json`""
$command = $Global:fusionCommand + $params
$vmPower = Invoke-Expression -Command $command | ConvertFrom-Json -ErrorAction Stop
} catch {
Write-host -ForegroundColor Red "Invalid VM Id $Id"
break
}
if($vmPower.power_state -eq "suspended") {
try {
Start-HostedVM -Id $Id
} catch {
Write-host -ForegroundColor Red "Unable to Resume VM $Id"
break
}
} else {
Write-Host "VM $Id is not Suspended"
}
}
Function New-HostedVM {
Param (
[parameter(Mandatory=$true,ValueFromPipeline=$true)][string]$ParentId,
[parameter(Mandatory=$true,ValueFromPipeline=$true)][string]$Name
)
if(!$Global:DefaultHostedServer) {
Write-Host -ForegroundColor Red "You are not connected to Hosted Server, please run Connect-HostedServer"
exit
}
$vm = Get-HostedVM -Id $ParentId
if($vm -match "Invalid VM Id") {
Write-host -ForegroundColor Red "Unable to find existing VM Id $ParentId"
break
}
$vmUri = $Global:DefaultHostedServer.Server + "/vms"
$body = @{"ParentId"="$ParentId";"Name"=$Name}
$body = $body | ConvertTo-Json
try {
Write-Host "Cloning VM $ParentId to $Name ..."
$params = "-UseBasicParsing -Headers `$Global:DefaultHostedServer.Headers -Uri $vmUri -Method POST -ContentType `"application/vnd.vmware.vmw.rest-v1+json`" -Body `$body"
$command = $Global:fusionCommand + $params
Invoke-Expression -Command $command | ConvertFrom-Json -ErrorAction Stop
} catch {
Write-host -ForegroundColor Red "Failed to Clone VM Id $ParentId"
break
}
}
Function Remove-HostedVM {
Param (
[parameter(Mandatory=$true,ValueFromPipeline=$true)][string]$Id,
[parameter(Mandatory=$false,ValueFromPipeline=$true)][boolean]$Confirm = $true
)
if(!$Global:DefaultHostedServer) {
Write-Host -ForegroundColor Red "You are not connected to Hosted Server, please run Connect-HostedServer"
exit
}
$vm = Get-HostedVM -Id $Id
if($vm -match "Invalid VM Id") {
Write-host -ForegroundColor Red "Unable to find existing VM Id $Id"
break
}
if($Confirm) {
Get-Confirmation
}
$vmUri = $Global:DefaultHostedServer.Server + "/vms/" + $Id
try {
Write-Host "Deleting VM Id $Id ..."
$params = "-UseBasicParsing -Headers `$Global:DefaultHostedServer.Headers -Uri $vmUri -Method DELETE -ContentType `"application/vnd.vmware.vmw.rest-v1+json`""
$command = $Global:fusionCommand + $params
Invoke-Expression -Command $command | ConvertFrom-Json -ErrorAction Stop
} catch {
Write-host -ForegroundColor Red "Failed to Delete VM Id $Id"
break
}
}
Function Get-HostedVMSharedFolder {
Param (
[parameter(Mandatory=$true,ValueFromPipeline=$true)][string]$Id
)
if(!$Global:DefaultHostedServer) {
Write-Host -ForegroundColor Red "You are not connected to Hosted Server, please run Connect-HostedServer"
exit
}
$folderUri = $Global:DefaultHostedServer.Server + "/vms/" + $Id + "/sharedfolders"
try {
$params = "-UseBasicParsing -Headers `$Global:DefaultHostedServer.Headers -Uri $folderUri -Method GET -ContentType `"application/vnd.vmware.vmw.rest-v1+json`""
$command = $Global:fusionCommand + $params
Invoke-Expression -Command $command | ConvertFrom-Json -ErrorAction Stop
} catch {
Write-host -ForegroundColor Red "Invalid VM Id $Id"
break
}
}
Function New-HostedVMSharedFolder {
Param (
[parameter(Mandatory=$true,ValueFromPipeline=$true)][string]$Id,
[parameter(Mandatory=$true,ValueFromPipeline=$true)][string]$FolderName,
[parameter(Mandatory=$true,ValueFromPipeline=$true)][string]$HostPath
)
if(!$Global:DefaultHostedServer) {
Write-Host -ForegroundColor Red "You are not connected to Hosted Server, please run Connect-HostedServer"
exit
}
$body = @{"folder_id"="$FolderName";"host_path"=$HostPath;"flags"=4}
$body = $body | ConvertTo-Json
$folderUri = $Global:DefaultHostedServer.Server + "/vms/" + $Id + "/sharedfolders"
try {
Write-Host "Creating new Shared Folder $FolderName to $HostPath for VM Id $Id ..."
$params += "-UseBasicParsing -Headers `$Global:DefaultHostedServer.Headers -Uri $folderUri -Method POST -ContentType `"application/vnd.vmware.vmw.rest-v1+json`" -Body `$body"
$command = $Global:fusionCommand + $params
Invoke-Expression -Command $command | ConvertFrom-Json -ErrorAction Stop
} catch {
Write-host -ForegroundColor Red "Failed to create Shared Folder for VM Id $Id"
break
}
}
Function Remove-HostedVMSharedFolder {
Param (
[parameter(Mandatory=$true,ValueFromPipeline=$true)][string]$Id,
[parameter(Mandatory=$true,ValueFromPipeline=$true)][string]$FolderName,
[parameter(Mandatory=$false,ValueFromPipeline=$true)][boolean]$Confirm = $true
)
if(!$Global:DefaultHostedServer) {
Write-Host -ForegroundColor Red "You are not connected to Hosted Server, please run Connect-HostedServer"
exit
}
if($Confirm) {
Get-Confirmation
}
$folderUri = $Global:DefaultHostedServer.Server + "/vms/" + $Id + "/sharedfolders/" + $FolderName
try {
Write-Host "Removing Shared Folder $FolderName for VM Id $Id ..."
$params += "-UseBasicParsing -Headers `$Global:DefaultHostedServer.Headers -Uri $folderUri -Method DELETE -ContentType `"application/vnd.vmware.vmw.rest-v1+json`""
$command = $Global:fusionCommand + $params
Invoke-Expression -Command $command | ConvertFrom-Json -ErrorAction Stop
} catch {
Write-host -ForegroundColor Red "Failed to remove Shared Folder for VM Id $Id"
break
}
}
Function Get-HostedVMNic {
Param (
[parameter(Mandatory=$true,ValueFromPipeline=$true)][string]$Id
)
if(!$Global:DefaultHostedServer) {
Write-Host -ForegroundColor Red "You are not connected to Hosted Server, please run Connect-HostedServer"
exit
}
$vmNicUri = $Global:DefaultHostedServer.Server + "/vms/" + $Id + "/nic"
try {
$params += "-UseBasicParsing -Headers `$Global:DefaultHostedServer.Headers -Uri $vmNicUri -Method GET -ContentType `"application/vnd.vmware.vmw.rest-v1+json`""
$command = $Global:fusionCommand + $params
$vmNics = Invoke-Expression -Command $command | ConvertFrom-Json -ErrorAction Stop
} catch {
Write-host -ForegroundColor Red "Invalid VM Id $Id"
break
}
$results = @()
foreach ($vmNic in $vmNics.nics) {
$tmp = [pscustomobject] @{
Index = $vmNic.index;
Type = $vmNic.Type;
VMnet = $vmNic.Vmnet;
}
$results+=$tmp
}
$results
}
Function Get-HostedNetworks {
if(!$Global:DefaultHostedServer) {
Write-Host -ForegroundColor Red "You are not connected to Hosted Server, please run Connect-HostedServer"
exit
}
$networksUri = $Global:DefaultHostedServer.Server + "/vmnet"
try {
$params = "-UseBasicParsing -Headers `$Global:DefaultHostedServer.Headers -Uri $networksUri -Method GET -ContentType `"application/vnd.vmware.vmw.rest-v1+json`""
$command = $Global:fusionCommand + $params
$networks = Invoke-Expression -Command $command | ConvertFrom-Json -ErrorAction Stop
} catch {
Write-host -ForegroundColor Red "Unable to retrieve Networks"
break
}
$results = @()
foreach ($network in $networks.vmnets) {
$tmp = [pscustomobject] @{
Name = $network.Name;
Type = $network.Type;
DHCP = $network.Dhcp;
Network = $network.subnet;
Netmask = $network.mask;
}
$results+=$tmp
}
$results
}

View File

@@ -0,0 +1,98 @@
{
"Type": "AUTOMATED",
"Data": {
"Name": "ICFarmJson",
"DisplayName": "FarmJsonTest",
"AccessGroup": "Root",
"Description": "created IC Farm from PS via JSON",
"Enabled": null,
"Deleting": false,
"Settings": {
"DisconnectedSessionTimeoutPolicy" : "NEVER",
"DisconnectedSessionTimeoutMinutes" : 1,
"EmptySessionTimeoutPolicy" : "AFTER",
"EmptySessionTimeoutMinutes" : 1,
"LogoffAfterTimeout" : false
},
"Desktop": null,
"DisplayProtocolSettings": {
"DefaultDisplayProtocol" : "PCOIP",
"AllowDisplayProtocolOverride" : false,
"EnableHTMLAccess" : false
},
"ServerErrorThreshold": null,
"MirageConfigurationOverrides": {
"OverrideGlobalSetting" : false,
"Enabled" : false,
"Url" : null
}
},
"AutomatedFarmSpec": {
"ProvisioningType": "INSTANT_CLONE_ENGINE",
"VirtualCenter": null,
"RdsServerNamingSpec": {
"NamingMethod": "PATTERN",
"PatternNamingSettings": {
"NamingPattern": "ICFarmVMPS",
"MaxNumberOfRDSServers": 1
}
},
"VirtualCenterProvisioningSettings": {
"EnableProvisioning": true,
"StopProvisioningOnError": true,
"MinReadyVMsOnVComposerMaintenance": 0,
"VirtualCenterProvisioningData": {
"ParentVm": "vm-rdsh-ic",
"Snapshot": "snap_5",
"Datacenter": null,
"VmFolder": "Instant_Clone_VMs",
"HostOrCluster": "vimal-cluster",
"ResourcePool": "vimal-cluster"
},
"VirtualCenterStorageSettings": {
"Datastores": [
{
"Datastore": "Datastore1",
"StorageOvercommit": "UNBOUNDED"
}
],
"UseVSan": false,
"ViewComposerStorageSettings": {
"UseSeparateDatastoresReplicaAndOSDisks": false,
"ReplicaDiskDatastore": null,
"UseNativeSnapshots": false,
"SpaceReclamationSettings": {
"ReclaimVmDiskSpace": false,
"ReclamationThresholdGB": null,
"BlackoutTimes": null
}
}
},
"VirtualCenterNetworkingSettings": {
"Nics": null
}
},
"VirtualCenterManagedCommonSettings": {
"TransparentPageSharingScope": "VM"
},
"CustomizationSettings": {
"CustomizationType": "CLONE_PREP",
"DomainAdministrator": null,
"AdContainer": "CN=Computers",
"ReusePreExistingAccounts": false,
"ClonePrepCustomizationSettings": {
"InstantCloneEngineDomainAdministrator": null,
"PowerOffScriptName": null,
"PowerOffScriptParameters": null,
"PostSynchronizationScriptName": null,
"PostSynchronizationScriptParameters": null
}
},
"RdsServerMaxSessionsData": {
"MaxSessionsType": "UNLIMITED",
"MaxSessions": null
}
},
"ManualFarmSpec": null,
"NetBiosName" : "ad-vimalg"
}

View File

@@ -1,17 +1,31 @@
{
"Type": "AUTOMATED",
"Data": {
"Name": "LCFarmTest",
"DisplayName": "Ankit LC Farm Test",
"Name": "LCFarmJson",
"DisplayName": "FarmJsonTest",
"AccessGroup": "Root",
"Description": "created LC Farm from PS",
"Description": "created LC Farm from PS via JSON",
"Enabled": null,
"Deleting": false,
"Settings": null,
"Settings": {
"DisconnectedSessionTimeoutPolicy" : "NEVER",
"DisconnectedSessionTimeoutMinutes" : 1,
"EmptySessionTimeoutPolicy" : "AFTER",
"EmptySessionTimeoutMinutes" : 1,
"LogoffAfterTimeout" : false
},
"Desktop": null,
"DisplayProtocolSettings": null,
"DisplayProtocolSettings": {
"DefaultDisplayProtocol" : "PCOIP",
"AllowDisplayProtocolOverride" : false,
"EnableHTMLAccess" : false
},
"ServerErrorThreshold": null,
"MirageConfigurationOverrides": null
"MirageConfigurationOverrides": {
"OverrideGlobalSetting" : false,
"Enabled" : false,
"Url" : null
}
},
"AutomatedFarmSpec": {
"ProvisioningType": "VIEW_COMPOSER",
@@ -19,7 +33,7 @@
"RdsServerNamingSpec": {
"NamingMethod": "PATTERN",
"PatternNamingSettings": {
"NamingPattern": "LCFarmVM_PS",
"NamingPattern": "LCFarmVMPS",
"MaxNumberOfRDSServers": 1
}
},
@@ -28,17 +42,17 @@
"StopProvisioningOnError": true,
"MinReadyVMsOnVComposerMaintenance": 0,
"VirtualCenterProvisioningData": {
"ParentVm": "Win_Server_2012_R2",
"Snapshot": "Snap_RDS",
"ParentVm": "RDSServer",
"Snapshot": "RDS_SNAP1",
"Datacenter": null,
"VmFolder": "AnkitPoolVM",
"HostOrCluster": "cls",
"ResourcePool": "cls"
"VmFolder": "Praveen",
"HostOrCluster": "CS-1",
"ResourcePool": "CS-1"
},
"VirtualCenterStorageSettings": {
"Datastores": [
{
"Datastore": "datastore1 (5)",
"Datastore": "Datastore1",
"StorageOvercommit": "UNBOUNDED"
}
],
@@ -67,7 +81,7 @@
"AdContainer": "CN=Computers",
"ReusePreExistingAccounts": false,
"SysprepCustomizationSettings": {
"CustomizationSpec": "RDSH_Cust2"
"CustomizationSpec": "PraveenCust"
}
},
"RdsServerMaxSessionsData": {
@@ -76,5 +90,5 @@
}
},
"ManualFarmSpec": null,
"NetBiosName" : "adankit"
"NetBiosName" : "adviewdev"
}

View File

@@ -7,17 +7,31 @@
"Description": "Manual PS Test",
"Enabled": null,
"Deleting": false,
"Settings": null,
"Settings": {
"DisconnectedSessionTimeoutPolicy" : "NEVER",
"DisconnectedSessionTimeoutMinutes" : 1,
"EmptySessionTimeoutPolicy" : "AFTER",
"EmptySessionTimeoutMinutes" : 1,
"LogoffAfterTimeout" : false
},
"Desktop": null,
"DisplayProtocolSettings": null,
"DisplayProtocolSettings": {
"DefaultDisplayProtocol" : "PCOIP",
"AllowDisplayProtocolOverride" : false,
"EnableHTMLAccess" : false
},
"ServerErrorThreshold": null,
"MirageConfigurationOverrides": null
"MirageConfigurationOverrides": {
"OverrideGlobalSetting" : false,
"Enabled" : false,
"Url" : null
}
},
"AutomatedFarmSpec": null,
"ManualFarmSpec": {
"RdsServers": [
{
"rdsServer": "WIN-ORKA1Q8B0P7"
"rdsServer": "RDSServer.adviewdev.eng.vmware.com"
}
]
}

View File

@@ -5,7 +5,44 @@
"AccessGroup": "Root",
"Description": "create full clone via JSON"
},
"DesktopSettings": null,
"DesktopSettings": {
"enabled": true,
"deleting": false,
"connectionServerRestrictions": null,
"logoffSettings": {
"powerPolicy": "TAKE_NO_POWER_ACTION",
"automaticLogoffPolicy": "NEVER",
"automaticLogoffMinutes": 120,
"allowUsersToResetMachines": false,
"allowMultipleSessionsPerUser": false,
"deleteOrRefreshMachineAfterLogoff": "NEVER",
"refreshOsDiskAfterLogoff": "NEVER",
"refreshPeriodDaysForReplicaOsDisk": 5,
"refreshThresholdPercentageForReplicaOsDisk": 10
},
"displayProtocolSettings": {
"supportedDisplayProtocols": ["PCOIP", "BLAST" ],
"defaultDisplayProtocol": "BLAST",
"allowUsersToChooseProtocol": true,
"pcoipDisplaySettings": {
"renderer3D": "DISABLED",
"enableGRIDvGPUs": false,
"vRamSizeMB": 96,
"maxNumberOfMonitors": 3,
"maxResolutionOfAnyOneMonitor": "WSXGA_PLUS"
},
"enableHTMLAccess": true
},
"flashSettings": {
"quality": "NO_CONTROL",
"throttling": "DISABLED"
},
"mirageConfigurationOverrides": {
"overrideGlobalSetting": false,
"enabled": false,
"url": false
}
},
"Type": "AUTOMATED",
"AutomatedDesktopSpec": {
"ProvisioningType": "VIRTUAL_CENTER",
@@ -69,7 +106,7 @@
"NoCustomizationSettings": {
"DoNotPowerOnVMsAfterCreation": false
},
"SysprepCustomizationSettings": null,
"SysprepCustomizationSettings": {"customizationSpec" : "praveencust"},
"QuickprepCustomizationSettings": null,
"CloneprepCustomizationSettings": null
}
@@ -77,6 +114,5 @@
"ManualDesktopSpec": null,
"RdsDesktopSpec": null,
"GlobalEntitlementData": null,
"NetBiosName" : "adviewdev",
"SysPrepName" : "praveencust"
"NetBiosName" : "adviewdev"
}

View File

@@ -5,7 +5,44 @@
"AccessGroup": "ROOT",
"Description": "create instant pool"
},
"DesktopSettings": null,
"DesktopSettings": {
"enabled": true,
"deleting": false,
"connectionServerRestrictions": null,
"logoffSettings": {
"powerPolicy": "ALWAYS_POWERED_ON",
"automaticLogoffPolicy": "NEVER",
"automaticLogoffMinutes": 120,
"allowUsersToResetMachines": false,
"allowMultipleSessionsPerUser": false,
"deleteOrRefreshMachineAfterLogoff": "DELETE",
"refreshOsDiskAfterLogoff": "NEVER",
"refreshPeriodDaysForReplicaOsDisk": 5,
"refreshThresholdPercentageForReplicaOsDisk": 10
},
"displayProtocolSettings": {
"supportedDisplayProtocols": ["PCOIP", "BLAST" ],
"defaultDisplayProtocol": "BLAST",
"allowUsersToChooseProtocol": true,
"pcoipDisplaySettings": {
"renderer3D": "DISABLED",
"enableGRIDvGPUs": false,
"vRamSizeMB": 96,
"maxNumberOfMonitors": 3,
"maxResolutionOfAnyOneMonitor": "WSXGA_PLUS"
},
"enableHTMLAccess": true
},
"flashSettings": {
"quality": "NO_CONTROL",
"throttling": "DISABLED"
},
"mirageConfigurationOverrides": {
"overrideGlobalSetting": false,
"enabled": false,
"url": false
}
},
"Type": "AUTOMATED",
"AutomatedDesktopSpec": {
"ProvisioningType": "INSTANT_CLONE_ENGINE",

View File

@@ -5,7 +5,44 @@
"AccessGroup": "Root",
"Description": "created linkedclone pool from ps"
},
"DesktopSettings": null,
"DesktopSettings": {
"enabled": true,
"deleting": false,
"connectionServerRestrictions": null,
"logoffSettings": {
"powerPolicy": "TAKE_NO_POWER_ACTION",
"automaticLogoffPolicy": "NEVER",
"automaticLogoffMinutes": 120,
"allowUsersToResetMachines": false,
"allowMultipleSessionsPerUser": false,
"deleteOrRefreshMachineAfterLogoff": "NEVER",
"refreshOsDiskAfterLogoff": "NEVER",
"refreshPeriodDaysForReplicaOsDisk": 5,
"refreshThresholdPercentageForReplicaOsDisk": 10
},
"displayProtocolSettings": {
"supportedDisplayProtocols": ["RDP","PCOIP", "BLAST" ],
"defaultDisplayProtocol": "PCOIP",
"allowUsersToChooseProtocol": true,
"pcoipDisplaySettings": {
"renderer3D": "DISABLED",
"enableGRIDvGPUs": false,
"vRamSizeMB": 96,
"maxNumberOfMonitors": 3,
"maxResolutionOfAnyOneMonitor": "WSXGA_PLUS"
},
"enableHTMLAccess": true
},
"flashSettings": {
"quality": "NO_CONTROL",
"throttling": "DISABLED"
},
"mirageConfigurationOverrides": {
"overrideGlobalSetting": false,
"enabled": false,
"url": null
}
},
"Type": "AUTOMATED",
"AutomatedDesktopSpec": {
"ProvisioningType": "VIEW_COMPOSER",
@@ -33,7 +70,7 @@
"Template": null,
"ParentVm": "Agent_pra",
"Snapshot": "kb-hotfix",
"Datacenter": null,
"Datacenter": "Dev-Dc",
"VmFolder": "Praveen",
"HostOrCluster": "CS-1",
"ResourcePool": "CS-1"
@@ -52,7 +89,8 @@
"UseNativeSnapshots": false,
"SpaceReclamationSettings": {
"ReclaimVmDiskSpace": false,
"ReclamationThresholdGB": null
"ReclamationThresholdGB": null,
"BlackoutTimes" : null
},
"PersistentDiskSettings": {
"RedirectWindowsProfile": false,
@@ -75,19 +113,31 @@
}
},
"VirtualCenterNetworkingSettings": {
"Nics": null
"Nics": [
{
"Nic": "nicName",
"NetworkLabelAssignmentSpecs": [
{
"Enabled" : false,
"networkLabel" : null,
"maxLabelType" : null,
"maxLabel" : null
}
]
}
]
}
},
"VirtualCenterManagedCommonSettings": {
"TransparentPageSharingScope": "VM"
},
"CustomizationSettings": {
"CustomizationType": "QUICK_PREP",
"DomainAdministrator": null,
"CustomizationType": "SYS_PREP",
"DomainAdministrator": "administrator",
"AdContainer": "CN=Computers",
"ReusePreExistingAccounts": false,
"NoCustomizationSettings": null,
"SysprepCustomizationSettings": null,
"SysprepCustomizationSettings": {"customizationSpec" : "praveencust"},
"QuickprepCustomizationSettings": {
"PowerOffScriptName": null,
"PowerOffScriptParameters": null,
@@ -99,7 +149,6 @@
},
"ManualDesktopSpec": null,
"RdsDesktopSpec": null,
"GlobalEntitlementData": null,
"NetBiosName" : "adviewdev",
"SysPrepName" : "praveencust"
"GlobalEntitlementData": null,
"NetBiosName" : "adviewdev"
}

View File

@@ -5,7 +5,44 @@
"AccessGroup": "ROOT",
"Description": "Manual pool creation"
},
"DesktopSettings": null,
"DesktopSettings": {
"enabled": true,
"deleting": false,
"connectionServerRestrictions": null,
"logoffSettings": {
"powerPolicy": "TAKE_NO_POWER_ACTION",
"automaticLogoffPolicy": "NEVER",
"automaticLogoffMinutes": 120,
"allowUsersToResetMachines": false,
"allowMultipleSessionsPerUser": false,
"deleteOrRefreshMachineAfterLogoff": "NEVER",
"refreshOsDiskAfterLogoff": "NEVER",
"refreshPeriodDaysForReplicaOsDisk": 5,
"refreshThresholdPercentageForReplicaOsDisk": 10
},
"displayProtocolSettings": {
"supportedDisplayProtocols": ["PCOIP", "BLAST" ],
"defaultDisplayProtocol": "BLAST",
"allowUsersToChooseProtocol": true,
"pcoipDisplaySettings": {
"renderer3D": "DISABLED",
"enableGRIDvGPUs": false,
"vRamSizeMB": 96,
"maxNumberOfMonitors": 3,
"maxResolutionOfAnyOneMonitor": "WSXGA_PLUS"
},
"enableHTMLAccess": true
},
"flashSettings": {
"quality": "NO_CONTROL",
"throttling": "DISABLED"
},
"mirageConfigurationOverrides": {
"overrideGlobalSetting": false,
"enabled": false,
"url": false
}
},
"Type": "MANUAL",
"AutomatedDesktopSpec": null,
"ManualDesktopSpec": {
@@ -16,7 +53,7 @@
"Source": "VIRTUAL_CENTER",
"Machines": [
{
"Machine" : "PowerCLI-VM"
"Machine" : "Praveen_Agent"
}
],
"VirtualCenter": null,
@@ -32,4 +69,5 @@
},
"RdsDesktopSpec": null,
"GlobalEntitlementData": null
}

View File

@@ -0,0 +1,27 @@
{
"Base": {
"Name" : "RdsJson",
"DisplayName": "TestRDSPS",
"AccessGroup": "Root",
"Description": "Testing PS"
},
"DesktopSettings": {
"enabled": true,
"deleting": false,
"connectionServerRestrictions": null,
"logoffSettings": null,
"displayProtocolSettings": null,
"flashSettings": {
"quality": "NO_CONTROL",
"throttling": "DISABLED"
},
"mirageConfigurationOverrides": null
},
"Type": "RDS",
"AutomatedDesktopSpec": null,
"ManualDesktopSpec": null,
"RdsDesktopSpec": {
"Farm": "test1"
},
"GlobalEntitlementData": null
}

View File

@@ -1,16 +0,0 @@
{
"Base": {
"Name" : "RdsJson",
"DisplayName": "TestRDSPS",
"AccessGroup": "Root",
"Description": "Testing PS"
},
"DesktopSettings": null,
"Type": "RDS",
"AutomatedDesktopSpec": null,
"ManualDesktopSpec": null,
"RdsDesktopSpec": {
"Farm": "Farm2"
},
"GlobalEntitlementData": null
}

View File

@@ -0,0 +1,20 @@
Prerequisites/Steps to use this module:
1. This module only works for Horizon product E.g. Horizon 7.0.2 and later.
2. Install the latest version of Powershell, PowerCLI(6.5) or (later version via psgallery).
3. Import HorizonView module by running: Import-Module VMware.VimAutomation.HorizonView.
4. Import "VMware.Hv.Helper" module by running: Import-Module -Name "location of this module" or Get-Module -ListAvailable 'VMware.Hv.Helper' | Import-Module.
5. Get-Command -Module "This module Name" to list all available functions or Get-Command -Module 'VMware.Hv.Helper'.
# Example script to connect view API service of Connection Server:
Import-Module VMware.VimAutomation.HorizonView
# Connection to view API service
$hvServer = Connect-HVServer -server <connection server IP/FQDN>
$hvServices = $hvserver.ExtensionData
$csList = $hvServices.ConnectionServer.ConnectionServer_List()
# Load this module
Get-Module -ListAvailable 'VMware.Hv.Helper' | Import-Module
Get-Command -Module 'VMware.Hv.Helper'
# Use advanced functions of this module
New-HVPool -spec 'path to InstantClone.json file'

View File

@@ -0,0 +1,22 @@
{
"generalData.clientMaxSessionTimePolicy": "TIMEOUT_AFTER",
"generalData.clientMaxSessionTimeMinutes": 600,
"generalData.clientIdleSessionTimeoutPolicy": "NEVER",
"generalData.clientIdleSessionTimeoutMinutes": null,
"generalData.clientSessionTimeoutMinutes": 1200,
"generalData.desktopSSOTimeoutPolicy": "DISABLE_AFTER",
"generalData.desktopSSOTimeoutMinutes": 15,
"generalData.applicationSSOTimeoutPolicy": "ALWAYS_ENABLED",
"generalData.applicationSSOTimeoutMinutes": null,
"generalData.viewAPISessionTimeoutMinutes": 10,
"generalData.preLoginMessage": null,
"generalData.displayWarningBeforeForcedLogoff": true,
"generalData.forcedLogoffTimeoutMinutes": 5,
"generalData.forcedLogoffMessage": "Your desktop is scheduled for an important update and will shut down in 5 minutes. Please save any unsaved work now",
"generalData.enableServerInSingleUserMode": false,
"generalData.storeCALOnBroker": false,
"generalData.storeCALOnClient": false,
"securityData.reauthSecureTunnelAfterInterruption": true,
"securityData.messageSecurityMode": "ENHANCED",
"securityData.enableIPSecForSecurityServerPairing": true
}

View File

@@ -27,6 +27,10 @@
<TableColumnHeader>
<Width>16</Width>
<Label>User Assignment</Label>
</TableColumnHeader>
<TableColumnHeader>
<Width>8</Width>
<Label>Entitled</Label>
</TableColumnHeader>
<TableColumnHeader>
<Width>7</Width>
@@ -56,10 +60,23 @@
<TableColumnItem>
<ScriptBlock>$_.desktopSummaryData.userAssignment</ScriptBlock>
</TableColumnItem>
<TableColumnItem>
<TableColumnItem>
<ScriptBlock>
$filterContains = Get-HVQueryFilter localData.desktops -contains ([VMware.Hv.DesktopId[]]$_.id)
$GlobalfilterContains = Get-HVQueryFilter localData.desktops -contains ([VMware.Hv.DesktopId[]]$_.id)
Try {
$results += Get-HVQueryResult -EntityType EntitledUserOrGroupLocalSummaryView -Filter $filterContains
$results += Get-HVQueryResult -EntityType EntitledUserOrGroupGlobalSummaryView -Filter $GlobalfilterContains
} Catch {
#Do nothing
}
$results.length
</ScriptBlock>
</TableColumnItem>
<TableColumnItem>
<ScriptBlock>$_.desktopSummaryData.enabled</ScriptBlock>
</TableColumnItem>
<TableColumnItem>
<TableColumnItem>
<ScriptBlock>$_.desktopSummaryData.numSessions</ScriptBlock>
</TableColumnItem>
</TableColumnItems>
@@ -97,6 +114,20 @@
<ScriptBlock>$_.desktopSummaryData.userAssignment</ScriptBlock>
</ListItem>
<ListItem>
<Label>Entitled</Label>
<ScriptBlock>
$filterContains = Get-HVQueryFilter localData.desktops -contains ([VMware.Hv.DesktopId[]]$_.id)
$GlobalfilterContains = Get-HVQueryFilter localData.desktops -contains ([VMware.Hv.DesktopId[]]$_.id)
Try {
$results += Get-HVQueryResult -EntityType EntitledUserOrGroupLocalSummaryView -Filter $filterContains
$results += Get-HVQueryResult -EntityType EntitledUserOrGroupGlobalSummaryView -Filter $GlobalfilterContains
} Catch {
#Do nothing
}
$results.length
</ScriptBlock>
</ListItem>
<ListItem>
<Label>Enabled</Label>
<ScriptBlock>$_.desktopSummaryData.enabled</ScriptBlock>
</ListItem>

View File

@@ -12,7 +12,7 @@
# RootModule = ''
# Version number of this module.
ModuleVersion = '1.0'
ModuleVersion = '1.1'
# ID used to uniquely identify this module
GUID = '6d3f7fb5-4e52-43d8-91e1-f65f72532a1d'

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,310 @@
<#
Copyright 2018 VMware, Inc. All rights reserved.
#>
# Class to manage Host resources
Class HostResource {
[VMware.VimAutomation.Types.VMHost] $vmhost
[string] $vcname
[string] $clustername
[string] $dcname
[string] $hostname
[string] $apitype
[string] $powerstatus
[string] $productname
[string] $version
[string] $fullname
[string] $connectionstatus
[string] $checkRelease
[int] $port
[Array] $ComponentResource = @()
[Array] $JsonProperties = @('__type__', 'dcname', 'vcname','clustername','hostname', 'apitype',
'powerstatus', 'productname', 'version', 'fullname', 'connectionstatus','checkRelease')
HostResource(
[VMware.VimAutomation.Types.VMHost] $vmhost) {
$this.vmhost = $vmhost
$view =$vmhost|Get-View
$vCenter_IP = $view.Summary.ManagementServerIp
if($vCenter_IP){
$this.vcname =$vCenter_IP
$this.dcname = (Get-Datacenter -VMHost $vmhost).Name
$this.clustername = (Get-Cluster -VMHost $vmhost).Name
}else{
$this.vcname =$this.vmhost.Name
}
$this.hostname = $this.vmhost.Name
$summary = $this.vmhost.ExtensionData.Summary
$this.powerstatus = $summary.runtime.powerState
$this.connectionstatus = $summary.runtime.connectionState
$this.apitype = $summary.Config.Product.apiType
$this.fullname = $summary.Config.Product.FullName
$this.version = $summary.Config.Product.version
$this.productname = $summary.Config.Product.licenseProductName
$this.port = 443
}
[Array] query_components() {
if ($this.ComponentResource.Count -eq 0) {
# Get server info
for($count_retry=0;$count_retry -lt 3;$count_retry ++){
try{
$svrResoure = [ServerResource]::new()
$svrResoure.set_data($this.vmhost)
$this.ComponentResource += $svrResoure
break
}catch{
error('query components server for '+$this.vmhost.Name +' error, retry it ' +($count_retry+1) +' times')
}
}
# Get PCI devices
for($count_retry=0;$count_retry -lt 3;$count_retry ++){
try{
$this.query_pcidevices()
break
}catch{
error('query components pcidevice for '+$this.vmhost.Name +' error, retry it ' +($count_retry+1) +' times')
if($count_retry -eq 2){
error('query components pcidevice for '+$this.vmhost.Name +' faild')
}
}
}
}
return $this.ComponentResource
}
[void] query_pcidevices() {
$EsxCliV2 = Get-EsxCli -V2 -VMHost $this.vmhost
$AllPciDevice = $EsxCliV2.hardware.pci.list.invoke()
foreach ($Pci in $AllPciDevice) {
# Ignore USB controllers, iLO/iDRAC devices
if ($Pci.DeviceName -like "*USB*" -or $Pci.DeviceName -like "*iLO*" -or $Pci.DeviceName -like "*iDRAC*") {
continue
}
# Get the NICs and storage adapters.
# We found NIC and storage adapters usually have module ID other than 0 or 1
$pciDevice = [IoDeviceResource]::new()
if ($Pci.ModuleID -ne 0 -and $Pci.ModuleID -ne -1) {
if (!$this.is_pcidevice_exist($Pci)) {
$pciDevice.set_data($Pci, $EsxCliV2)
$this.ComponentResource += $pciDevice
}
}
}
}
[boolean] is_pcidevice_exist($device) {
foreach ($pci in $this.ComponentResource) {
if ($pci.psobject.TypeNames[0] -eq "IoDeviceResource") {
$vid = [String]::Format("{0:x4}", [int]$device.VendorID)
$did = [String]::Format("{0:x4}", [int]$device.DeviceID)
$svid = [String]::Format("{0:x4}", [int]$device.SubVendorID)
$ssid = [String]::Format("{0:x4}", [int]$device.SubDeviceID)
if ($pci.vid -eq $vid -and $pci.did -eq $did -and
$pci.svid -eq $svid -and $pci.ssid -eq $ssid) {
return $true
}
}
}
return $false
}
[object] to_jsonobj() {
$Json = $this | Select-Object -Property $this.JsonProperties
$ComponentChildren = @()
$this.ComponentResource | ForEach-Object {$ComponentChildren += $_.to_jsonobj()}
$Json | Add-Member -Name "ComponentResource" -Value $ComponentChildren -MemberType NoteProperty
return $Json
}
[string] get_host_status() {
if ($this.powerstatus -and $this.powerstatus -ne 'unknown') {
return $this.powerstatus
}
if ($this.connectionstatus) {
return ("Server " + $this.connectionstatus)
}
else {
return "Server status is unknown"
}
}
[string] get_prompt_name() {
if ($this.apitype) {
$start = $this.apitype
}
else {
$start = "Host"
}
return $start + " " + $this.hostname
}
}
# Class to manage server resources
Class ServerResource {
[string] $type
[string] $model
[string] $vendor
[string] $biosversion
[string] $cpumodel
[string] $cpufeatureid
[string] $uuid
[string] $status
[array] $matchResult
[array] $warnings
[string] $vcgLink
[array] $updateRelease
[VMware.VimAutomation.Types.VMHost] $vmhost
[Array] $JsonProperties = @('__type__','type', 'model', 'vendor', 'biosversion',
'cpumodel', 'cpufeatureid', 'uuid','status','matchResult','warnings','vcgLink','updateRelease')
[void] set_data(
[VMware.VimAutomation.Types.VMHost] $vmhost) {
$this.vmhost = $vmhost
$this.type = "Server"
$this.model = $this.vmhost.Model
$this.vendor = $this.vmhost.Manufacturer
$this.biosversion = $this.vmhost.ExtensionData.Hardware.BiosInfo.BiosVersion
$this.cpumodel = $this.vmhost.ProcessorType
$cpuFeature = $this.vmhost.ExtensionData.Hardware.CpuFeature
if ($cpuFeature -and $cpuFeature.Count -gt 2) {
$this.cpufeatureid = $this.vmhost.ExtensionData.Hardware.CpuFeature[1].Eax
}
$this.uuid = $this.vmhost.ExtensionData.Hardware.systeminfo.uuid
}
[object] to_jsonobj() {
return $this | Select-Object -Property $this.JsonProperties
}
}
# Class to manage each IO device
Class IoDeviceResource {
[string] $type
[string] $model
[string] $deviceid
[string] $device
[string] $comptype
[string] $vid
[string] $did
[string] $svid
[string] $ssid
[string] $pciid
[string] $vendor
[string] $driver
[string] $driverversion
[string] $firmware
[string] $status
[array] $matchResult
[array] $warnings
[string] $vcgLink
[array] $updateRelease
[Array] $JsonProperties = @('__type__','type', 'model', 'deviceid', 'device',
'comptype', 'vid', 'did', 'svid', 'ssid', 'pciid',
'vendor', 'driver', 'driverversion', 'firmware','status','matchResult','warnings','vcgLink','updateRelease')
[void] set_data(
[object] $pci,
[object] $EsxCli) {
$this.type = "IO Device"
$this.model = $Pci.DeviceName
$this.deviceid = $pci.Address
$this.device = $pci.VMKernelName
$this.vid = [String]::Format("{0:x4}", [int]$Pci.VendorID)
$this.did = [String]::Format("{0:x4}", [int]$Pci.DeviceID)
$this.svid = [String]::Format("{0:x4}", [int]$Pci.SubVendorID)
$this.ssid = [String]::Format("{0:x4}", [int]$Pci.SubDeviceID)
$this.pciid = $this.vid + ":" + $this.did + ":" + $this.svid + ":" + $this.ssid
$this.vendor = $pci.VendorName
$this.driver = $Pci.ModuleName
$this.driverversion = "N/A"
$this.firmware = "N/A"
# Set component type and driverversion, firmware
if ($this.device -match 'nic') {
$arg = @{}
$arg['nicname'] = $this.device
$nic = $EsxCli.network.nic.get.invoke($arg)
$this.comptype = "Physical NIC"
$this.driverversion = $nic.driverinfo.Version
$this.firmware = $nic.driverinfo.FirmwareVersion
}
elseif ($this.device -match 'hba') {
$arg = @{}
$arg['module'] = $this.driver
$module = $EsxCli.system.module.get.invoke($arg)
$this.comptype = "Storage Adapter"
$this.driverversion = $module.Version
}
}
[object] to_jsonobj() {
return $this | Select-Object -Property $this.JsonProperties
}
[string] get_id_detail() {
return $this.driver + " (PCIId:" + $this.pciid + ")"
}
}
# Class to manage IO device group
Class IoDeviceResourceGroup {
[Array] $iodevices = @()
[Array] $nics = @()
[Array] $adapters = @()
[void] append_nic([IODeviceResource] $nic) {
$this.iodevices += $nic
$this.nics += $nic
}
[void] append_storage_adapter([IODeviceResource] $adapter) {
$this.iodevices += $adapter
$this.adapters += $adapter
}
[boolean] has_nics() {
return $this.nics.Count > 0
}
[boolean] has_storage_adapters() {
return $this.adapters.Count > 0
}
}
#
# Collect hardware inventory data from all the hosts
#
Function Get-VCGHWInfo {
Param(
[Parameter(Mandatory=$true)] $vmHosts
)
# Collect the hardware data
$Data = @()
foreach($vmHost in $vmHosts) {
$vm = [HostResource]::new($vmHost)
try {
info ("Collecting hardware data from " + $vm.hostname)
$null = $vm.query_components()
if($vm.powerstatus -eq 'poweredOn' -and $vm.connectionstatus -eq 'connected'){
$Data += $vm
info ("Collecting hardware data from " + $vm.hostname +' success')
}
}
catch {
error ("Failed to collect hardware data from " + $vm.hostname)
}
}
return $Data
}

View File

@@ -0,0 +1,168 @@
$Uuid = [guid]::NewGuid()
$Headers = New-Object "System.Collections.Generic.Dictionary[[String],[String]]"
$Headers.add("x-request-id", $Uuid)
$Headers.add("x-api-toolid", "180209100001")
$Headers.add("x-api-key", "SJyb8QjK2L")
$Url_Perfix = 'https://apigw.vmware.com/m4/compatibility/v1'
$Url = $Url_Perfix + "/compatible/servers/search?"
$UrlPci = $Url_Perfix + "/compatible/iodevices/search?"
$apiQurryDict=@{}
#
# Ping remote api server.
#
Function PingApiServer(){
$apiServerIp='apigw.vmware.com'
$results =Test-Connection $apiServerIp -Quiet
if($results -ne $true){
error ("Failed to access VMware Compatibility API,
Unable to use comparison function, only view basic hardware information;
you can use 'Get-VCGHWInfo -g <fileName>' create hardware json,
then use 'Check-VCGStatus -f <fileName>' load hardware json file to comapre when connect an available network")
Exit(1)
}
}
#
# Get the web request.
#
Function Get-WebRequest($VCGurl) {
try {
$req = Invoke-WebRequest -Headers $Headers -Uri $VCGUrl -ErrorVariable $err -UseBasicParsing
}
catch {
if ($err[0].errorrecord.exception.response) {
error ("WebReponse code:" + $err[0].errorrecord.exception.response.statuscode.value__)
error ($exitScript)
Exit(1)
}
else {
error ("Failed to check " + $type + " data for " + $HostResource.hostname)
error ("Failed to access VMware Compatibility API, please check your Internet connection or contact VMware Compatibility API administrator")
error ("Exit the script")
Exit(1)
}
}
return $req
}
Function Get-RemoteApiTitleString([object]$device,$EsxiVersion){
if ($device.type -eq 'Server') {
$Title = $device.model + $device.vendor + $device.cpufeatureid + $device.biosversion +$EsxiVersion
}
else{
$Title = $device.vid + $device.did + $device.Svid + $device.Ssid + $EsxiVersion
}
return $Title
}
Function Get-ResponseFromApi([object]$device,$EsxiVersion){
if ($device.type -eq 'Server') {
$VCGUrl = $Url + "model=" + $device.model + "&releaseversion=" + $EsxiVersion `
+ "&vendor=" + $device.vendor + "&cpuFeatureId=" + $device.cpufeatureid `
+ "&bios=" + $device.biosversion
debug ("Model:" + $device.model)
debug ("VCG Url:" + $VCGUrl)
$Headers.GetEnumerator() | ForEach-Object {debug ("Req Header:" + $_.key + ":" + $_.value)}
$request = Get-WebRequest $VCGUrl
$Response = ConvertFrom-Json -InputObject $request -Erroraction 'silentlycontinue'
}
elseif ($device.type -eq 'IO Device') {
$VCGUrl = $UrlPci + "vid=0X" + $device.vid + "&did=0X" + $device.did + "&svid=0X" + $device.Svid `
+ "&ssid=0X" + $device.Ssid + "&releaseversion=" + $EsxiVersion `
+ "&driver=" + $device.Driver + "&driverversion=" + $device.driverversion + "&firmware=N/A"
debug ("Model:" + $device.model)
debug ("VCG Url:" + $VCGUrl)
$Headers.GetEnumerator() | ForEach-Object {debug ("Req Header:" + $_.key + ":" + $_.value)}
$request = Get-WebRequest $VCGUrl
$Response = ConvertFrom-Json -InputObject $request -Erroraction 'silentlycontinue'
}
return $Response
}
#
# Get the data from api
#
Function Get-VCGData($HostResource) {
foreach ($device in $HostResource.ComponentResource) {
if ($HostResource.checkRelease) {
$EsxiVersion = $HostResource.checkRelease
}
else {
$EsxiVersion = $HostResource.version
}
$temp=0
$title=Get-RemoteApiTitleString $device $EsxiVersion
if($apiQurryDict.Count -eq 0){
$Response= Get-ResponseFromApi $device $EsxiVersion
$apiQurryDict.Add($title,$Response)
}else{
foreach($onetitle in $apiQurryDict.keys){
if($onetitle -eq $title){
$Response= $apiQurryDict[$onetitle]
$temp=1
break
}
}
if($temp -eq 0){
$Response= Get-ResponseFromApi $device $EsxiVersion
$apiQurryDict.Add($title,$Response)
}
}
if ($Response.matches) {
foreach ($match in $Response.matches) {
$device.vcgLink += [string]$match.vcgLink
}
}
else {
foreach ($potentialMatche in $Response.potentialMatches) {
$device.vcgLink += [string]$potentialMatche.vcgLink
}
}
$device.status = [string]$Response.searchResult.status
$device.matchResult = [string]$Response.searchResult.matchResult
$device.warnings = $Response.searchResult.warnings
$device.updateRelease = [string]$Response.searchOption.foundRelease
}
}
#
# Send the hardware data to VCG API and handle returned result
#
Function Get-DataFromRemoteApi([object]$servers) {
info ("Checking hardware compatibility result with VMware Compatibility Guide API...")
info ("This may take a few minutes depending on your network.")
for ($idx = 0; $idx -lt $servers.Count; $idx++) {
$server = $servers[$idx]
$i = $idx + 1
info ([string]$i + "/" + [string]$servers.Count + " - Checking hardware compatibility results for " + $server.hostname)
if (!$server -or $server.ComponentResource.Count -eq 0) {
error('Failed to get the hardware info.')
Exit(1)
}
Get-VCGData $server
}
return $servers
}
Function Get-VCGStatus{
Param(
[Parameter(Mandatory=$true)] $Data,
[Parameter(Mandatory=$false)] $Version
)
$checkRelease = $Version
PingApiServer
foreach ($vmHost in $Data) {
# $vmHost|add-member -Name "checkRelease" -value $checkRelease -MemberType NoteProperty -Force
$vmHost.checkRelease=$checkRelease
}
$results = Get-DataFromRemoteApi($Data)
if ($results.Count -eq 0) {
error ("Failed to get compatibility results. No report will be generated")
error ("Exit the script")
Exit(1)
}
return $results
}

View File

@@ -0,0 +1,41 @@
# About
This module is designed to ease the work of collecting hardware inventory data and compare it with VMware's official VCG data. Before deploying vSphere, it is required to validate your physical machines with VCG to make sure all the devices in your physical machines are compatible with the vSphere version you want to install. It is a time-consuming and painful experience to collect hardware/driver/firmware data from all of the machines, especially when you have a huge number of machines in your data center.
# How It Works
By using this module, it will automate the data collection and comparison work.
When running the module, it will connect to the target vCenter or ESXi to read the hardware data. It is a read-only operation and nothing on the target hosts will be changed. There is almost no impact on the machine's performance as the read operation takes just few seconds.
The module will then send your hardware inventory data to VMware's offical website to conduct a compatibility check. The result will be 'Compatible', 'May not be compatible' or 'Not compatible'.
* Compatible: the hardware is compatible with the given vSphere release. Link to that VCG page will be provided.
* May not be compatible: manual check is required to confirm the compatibility status of this hardware. A few potential matching VCG records will be provided.
* Not compatible: the hardware is not compatible with the given vSphere release.
After the checking is completed, the module will generate reports in different formats for your review and future use. A summary view in html will give you an overview of your machines compatibility status; an html file with device details to view each device/driver/firmware you have, their compatibility with vSphere version you specified and links to the corresponding VCG documents online; a csv file with device details to allow customization on report in Excel or by your own tool.
# Usage
Considering many data center may have control on internet access, we create 3 cmdlets to meet various situations.
* Get-VCGHWInfo: cmdlet to collect hardware info
* Get-VCGStatus: cmdlet to check hardware compatibility by query VCG website
* Export-VCGReport: cmdlet to export the summary/html/csv reports
1. You need to first import this module after you import PowerCLI module
PS> Import-Module &lt;path_to_VMware.VCGChecker.psd1>
2. Connect to the target vSphere hosts using Connect-VIServer and get VMHosts
PS> Connect-VIServer -Server &lt;server> -User &lt;username> -Password &lt;password>
PS> $vmhosts = Get-VMHost
3. Collect the hardware data
PS> $hwdata = Get-VCGHWInfo -vmHosts $vmhosts
Note: if you don't have internet access, you need to connect your client to internet before proceeding to the next step.
4. Specify the target vSphere release you want to check and submit the hardware data to VMware website
PS> $vcgdata= Get-VCGStatus -Data $hwdata -Version '&lt;release>'
5. Save the compatibility reports
PS> Export-VCGReport -Data $vcgdata -Dir &lt;dir>
# Known Limitation
* The module is not able to get the firmware version for HBA devices.
* The module is not able to get the HDD/SSD data.

View File

@@ -0,0 +1,17 @@
Function Save-VCGJsonFile{
Param(
[Parameter(Mandatory=$true)] $FileName,
[Parameter(Mandatory=$true)] $Data,
[Parameter(Mandatory=$true)] $Dir
)
$json = @()
$Data | ForEach-Object { $json += $_.to_jsonobj()}
if (!(Test-Path $Dir)) {
New-Item -Type directory -Confirm:$false -Path $Dir -Force |Out-Null
}
$Path= $Dir + '\' + $FileName + '.json'
info ("Saving data to " + $Path)
ConvertTo-Json -Depth 10 -Compress $json | Out-File -encoding 'UTF8' -FilePath $Path
}

View File

@@ -0,0 +1,90 @@
#
# Module manifest for module 'VMware.VCGChecker'
#
# Generated by: fdai@vmware.com, zhangta@vmware.com, linweij@vmware.com
#
# Generated on: 11/15/18
#
@{
# Script module or binary module file associated with this manifest.
# RootModule = 'VMware.VCGChecker.psm1'
# Version number of this module.
ModuleVersion = '1.0.0'
# Supported PSEditions
# CompatiblePSEditions = @()
# ID used to uniquely identify this module
# GUID = ''
# Author of this module
Author = 'Frank Dai, Tao Zhang, Linwei Jiang'
# Company or vendor of this module
CompanyName = 'VMware'
# Copyright statement for this module
Copyright = '(c) 2018 VMware. All rights reserved.'
# Description of the functionality provided by this module
Description = 'PowerShell Module for Checking Hardware Compatibility Status'
RequiredModules = @('VMware.VimAutomation.Core')
# Modules to import as nested modules of the module specified in RootModule/ModuleToProcess
NestedModules = 'Get-VCGHWInfo.ps1','Get-VCGStatus.ps1','Export-VCGReport.ps1', 'Save-VCGJsonFile.ps1', 'logger.ps1'
# Functions to export from this module, for best performance, do not use wildcards and do not delete the entry, use an empty array if there are no functions to export.
FunctionsToExport = 'Get-VCGHWInfo', 'Get-VCGStatus', 'Export-VCGReport', 'Save-VCGJsonFile'
# Cmdlets to export from this module, for best performance, do not use wildcards and do not delete the entry, use an empty array if there are no cmdlets to export.
CmdletsToExport = @()
# Variables to export from this module
VariablesToExport = '*'
# Aliases to export from this module, for best performance, do not use wildcards and do not delete the entry, use an empty array if there are no aliases to export.
AliasesToExport = @()
# DSC resources to export from this module
# DscResourcesToExport = @()
# List of all modules packaged with this module
# ModuleList = @()
# List of all files packaged with this module
# FileList = @()
# Private data to pass to the module specified in RootModule/ModuleToProcess. This may also contain a PSData hashtable with additional module metadata used by PowerShell.
PrivateData = @{
PSData = @{
# Tags applied to this module. These help with module discovery in online galleries.
# Tags = @()
# A URL to the license for this module.
# LicenseUri = ''
# A URL to the main website for this project.
# ProjectUri = ''
# A URL to an icon representing this module.
# IconUri = ''
# ReleaseNotes of this module
# ReleaseNotes = ''
} # End of PSData hashtable
} # End of PrivateData hashtable
# HelpInfo URI of this module
# HelpInfoURI = ''
# Default prefix for commands exported from this module. Override the default prefix using Import-Module -Prefix.
# DefaultCommandPrefix = ''
}

View File

@@ -0,0 +1,112 @@
<#
Copyright 2018 VMware, Inc. All rights reserved.
#>
# Messages
$HEADER_OK = "[OK] "
$HEADER_INFO = "[INFO] "
$HEADER_WARNING = "[WARNING] "
$HEADER_ERR = "[ERROR] "
Class DebugLog
{
# Static variables of the logger class
static [string] $CAFILE_PATH = "./.certs/"
[boolean] $debug
[string] $logfile
DebugLog()
{
$this.debug = $false
$this.logfile = $null
if (!(Test-Path $this::CAFILE_PATH))
{
New-Item -Type directory -Confirm:$false -Path $this::CAFILE_PATH
}
}
[void] SetDebug(
[boolean] $debug,
[string] $hostname
){
if (!$hostname) {$hostname = ''}
$this.debug = $debug
if ($this.debug)
{
$this.logfile = $this::CAFILE_PATH + $hostname + [DateTime]::Now.ToString("_yyyy-MM-dd_HH-mm") + ".log"
}else{
$this.logfile = $null
}
}
[void] log_vars(
[string] $message,
[object] $var
){
$this.log($message + $var)
}
[void] log(
[string] $message
){
if (!$this.debug -or !$this.logfile) {return}
try
{
$message | Out-File $this.logfile -Append
}catch {
Out-Host -InputObject ("[Exception] Failed to write to a logfile: " + $this.logfile)
Out-Host -InputObject $_
}
}
}
Function debug_vars(
[string] $message,
[object] $var)
{
$logger.log_vars($message, $var)
}
Function debug(
[string] $message)
{
$logger.log($message)
}
Function vcglog(
[string] $message,
[string] $header="")
{
$msg = $header + $message
$logger.log($msg)
Out-Host -InputObject $msg
}
Function ok(
[string] $message)
{
vcglog $message $HEADER_OK
}
Function warning(
[string] $message)
{
vcglog $message $HEADER_WARNING
}
Function info(
[string] $message)
{
vcglog $message $HEADER_INFO
}
Function error(
[string] $message)
{
vcglog $message $HEADER_ERR
}
$logger = [DebugLog]::new()
$logger.SetDebug($true, "vcc-debug")

View File

@@ -0,0 +1,88 @@
#
# Module manifest for module 'VMware.VMC.NSXT'
#
# Generated by: wlam@vmware.com
#
# Generated on: 09/11/18
#
@{
# Script module or binary module file associated with this manifest.
RootModule = 'VMware.VMC.NSXT.psm1'
# Version number of this module.
ModuleVersion = '1.0.0'
# Supported PSEditions
# CompatiblePSEditions = @()
# ID used to uniquely identify this module
GUID = 'c094608a-7480-4751-a14c-c9dd68870607'
# Author of this module
Author = 'William Lam'
# Company or vendor of this module
CompanyName = 'VMware'
# Copyright statement for this module
Copyright = '(c) 2018 VMware. All rights reserved.'
# Description of the functionality provided by this module
Description = 'PowerShell Module for Managing NSX-T on VMware Cloud on AWS'
# Minimum version of the Windows PowerShell engine required by this module
PowerShellVersion = '6.0'
# Functions to export from this module, for best performance, do not use wildcards and do not delete the entry, use an empty array if there are no functions to export.
FunctionsToExport = 'Connect-NSXTProxy', 'Get-NSXTSegment', 'New-NSXTSegment', 'Remove-NSXTSegment', 'Get-NSXTGroup', 'New-NSXTGroup', 'Remove-NSXTGroup', 'Get-NSXTService', 'New-NSXTService', 'Get-NSXTFirewall', 'New-NSXTFirewall', 'Remove-NSXTFirewall'
# Cmdlets to export from this module, for best performance, do not use wildcards and do not delete the entry, use an empty array if there are no cmdlets to export.
CmdletsToExport = @()
# Variables to export from this module
VariablesToExport = '*'
# Aliases to export from this module, for best performance, do not use wildcards and do not delete the entry, use an empty array if there are no aliases to export.
AliasesToExport = @()
# DSC resources to export from this module
# DscResourcesToExport = @()
# List of all modules packaged with this module
# ModuleList = @()
# List of all files packaged with this module
# FileList = @()
# Private data to pass to the module specified in RootModule/ModuleToProcess. This may also contain a PSData hashtable with additional module metadata used by PowerShell.
PrivateData = @{
PSData = @{
# Tags applied to this module. These help with module discovery in online galleries.
# Tags = @()
# A URL to the license for this module.
# LicenseUri = ''
# A URL to the main website for this project.
# ProjectUri = ''
# A URL to an icon representing this module.
# IconUri = ''
# ReleaseNotes of this module
# ReleaseNotes = ''
} # End of PSData hashtable
} # End of PrivateData hashtable
# HelpInfo URI of this module
# HelpInfoURI = ''
# Default prefix for commands exported from this module. Override the default prefix using Import-Module -Prefix.
# DefaultCommandPrefix = ''
}

View File

@@ -0,0 +1,889 @@
Function Connect-NSXTProxy {
<#
.NOTES
===========================================================================
Created by: William Lam
Date: 09/11/2018
Organization: VMware
Blog: http://www.virtuallyghetto.com
Twitter: @lamw
===========================================================================
.SYNOPSIS
Retrieves NSX-T Proxy URL + acquire CSP Access Token to then be used with NSXT-T Policy API
.DESCRIPTION
This cmdlet creates $global:nsxtProxyConnection object containing the NSX-T Proxy URL along with CSP Token
.EXAMPLE
Connect-NSXTProxy -RefreshToken $RefreshToken -OrgName $OrgName -SDDCName $SDDCName
.NOTES
You must be logged into VMC using Connect-VmcServer cmdlet
#>
Param (
[Parameter(Mandatory=$true)][String]$RefreshToken,
[Parameter(Mandatory=$true)][String]$OrgName,
[Parameter(Mandatory=$true)][String]$SDDCName
)
If (-Not $global:DefaultVMCServers.IsConnected) { Write-error "No valid VMC Connection found, please use the Connect-VMC to connect"; break } Else {
$sddcService = Get-VmcService "com.vmware.vmc.orgs.sddcs"
$orgId = (Get-VMCOrg -Name $OrgName).Id
$sddcId = (Get-VMCSDDC -Name $SDDCName -Org $OrgName).Id
$sddc = $sddcService.get($orgId,$sddcId)
if($sddc.resource_config.nsxt) {
$nsxtProxyURL = $sddc.resource_config.nsx_api_public_endpoint_url
} else {
Write-Host -ForegroundColor Red "This is not an NSX-T based SDDC"
break
}
}
$results = Invoke-WebRequest -Uri "https://console.cloud.vmware.com/csp/gateway/am/api/auth/api-tokens/authorize?refresh_token=$RefreshToken" -Method POST -ContentType "application/json" -UseBasicParsing -Headers @{"csp-auth-token"="$RefreshToken"}
if($results.StatusCode -ne 200) {
Write-Host -ForegroundColor Red "Failed to retrieve Access Token, please ensure your VMC Refresh Token is valid and try again"
break
}
$accessToken = ($results | ConvertFrom-Json).access_token
$headers = @{
"csp-auth-token"="$accessToken"
"Content-Type"="application/json"
"Accept"="application/json"
}
$global:nsxtProxyConnection = new-object PSObject -Property @{
'Server' = $nsxtProxyURL
'headers' = $headers
}
$global:nsxtProxyConnection
}
Function Get-NSXTSegment {
<#
.NOTES
===========================================================================
Created by: William Lam
Date: 09/11/2018
Organization: VMware
Blog: http://www.virtuallyghetto.com
Twitter: @lamw
===========================================================================
.SYNOPSIS
Returns all NSX-T Segments (Logical Networks)
.DESCRIPTION
This cmdlet retrieves all NSX-T Segments (Logical Networks)
.EXAMPLE
Get-NSXTSegment
.EXAMPLE
Get-NSXTSegment -Name "sddc-cgw-network-1"
#>
Param (
[Parameter(Mandatory=$False)]$Name,
[Switch]$Troubleshoot
)
If (-Not $global:nsxtProxyConnection) { Write-error "No NSX-T Proxy Connection found, please use Connect-NSXTProxy" } Else {
$method = "GET"
$segmentsURL = $global:nsxtProxyConnection.Server + "/policy/api/v1/infra/networks/cgw/segments"
if($Troubleshoot) {
Write-Host -ForegroundColor cyan "`n[DEBUG] - $METHOD`n$segmentsURL`n"
}
try {
if($PSVersionTable.PSEdition -eq "Core") {
$requests = Invoke-WebRequest -Uri $segmentsURL -Method $method -Headers $global:nsxtProxyConnection.headers -SkipCertificateCheck
} else {
$requests = Invoke-WebRequest -Uri $segmentsURL -Method $method -Headers $global:nsxtProxyConnection.headers
}
} catch {
Write-Host -ForegroundColor Red "`nThe NSX-T Proxy session is no longer valid, please re-run the Connect-NSXTProxy cmdlet to retrieve a new token`n"
break
}
if($requests.StatusCode -eq 200) {
$segments = ($requests.Content | ConvertFrom-Json).results
if ($PSBoundParameters.ContainsKey("Name")){
$segments = $segments | where {$_.display_name -eq $Name}
}
$results = @()
foreach ($segment in $segments) {
$subnets = $segment.subnets
$network = $subnets.network
$gateway = $subnets.gateway_addresses
$dhcpRange = $subnets.dhcp_ranges
$tmp = [pscustomobject] @{
Name = $segment.display_name;
ID = $segment.Id;
Network = $network;
Gateway = $gateway;
DHCPRange = $dhcpRange;
}
$results+=$tmp
}
$results
} else {
Write-Error "Failed to retrieve NSX-T Segments"
}
}
}
Function New-NSXTSegment {
<#
.NOTES
===========================================================================
Created by: William Lam
Date: 09/11/2018
Organization: VMware
Blog: http://www.virtuallyghetto.com
Twitter: @lamw
===========================================================================
.SYNOPSIS
Creates a new NSX-T Segment (Logical Networks)
.DESCRIPTION
This cmdlet creates a new NSX-T Segment (Logical Networks)
.EXAMPLE
New-NSXTSegment -Name "sddc-cgw-network-4" -Gateway "192.168.4.1" -Prefix "24" -DHCP -DHCPRange "192.168.4.2-192.168.4.254"
#>
Param (
[Parameter(Mandatory=$True)]$Name,
[Parameter(Mandatory=$True)]$Gateway,
[Parameter(Mandatory=$True)]$Prefix,
[Parameter(Mandatory=$False)]$DHCPRange,
[Switch]$DHCP,
[Switch]$Troubleshoot
)
If (-Not $global:nsxtProxyConnection) { Write-error "No NSX-T Proxy Connection found, please use Connect-NSXTProxy" } Else {
if($DHCP) {
$dhcpConf = @($DHCPRange)
} else {
$dhcpConf = @($null)
}
$subnets = @{
gateway_addresses = @($gateway);
prefix_len = $Prefix;
dhcp_ranges = $dhcpConf
}
$payload = @{
display_name = $Name;
subnets = @($subnets)
}
$body = $payload | ConvertTo-Json -depth 4
$method = "PUT"
$newSegmentsURL = $global:nsxtProxyConnection.Server + "/policy/api/v1/infra/networks/cgw/segments/$Name"
if($Troubleshoot) {
Write-Host -ForegroundColor cyan "`n[DEBUG] - $method`n$newSegmentsURL`n"
Write-Host -ForegroundColor cyan "[DEBUG]`n$body`n"
}
try {
if($PSVersionTable.PSEdition -eq "Core") {
$requests = Invoke-WebRequest -Uri $newSegmentsURL -Body $body -Method $method -Headers $global:nsxtProxyConnection.headers -SkipCertificateCheck
} else {
$requests = Invoke-WebRequest -Uri $newSegmentsURL -Body $body -Method $method -Headers $global:nsxtProxyConnection.headers
}
} catch {
Write-Host -ForegroundColor Red "`nThe NSX-T Proxy session is no longer valid, please re-run the Connect-NSXTProxy cmdlet to retrieve a new token`n"
break
}
if($requests.StatusCode -eq 200) {
Write-Host "Succesfully created new NSX-T Segment $Name"
($requests.Content | ConvertFrom-Json) | select display_name, id
} else {
Write-Error "Failed to create new NSX-T Segment"
}
}
}
Function Remove-NSXTSegment {
<#
.NOTES
===========================================================================
Created by: William Lam
Date: 09/11/2018
Organization: VMware
Blog: http://www.virtuallyghetto.com
Twitter: @lamw
===========================================================================
.SYNOPSIS
Removes an NSX-T Segment (Logical Networks)
.DESCRIPTION
This cmdlet removes an NSX-T Segment (Logical Networks)
.EXAMPLE
Remove-NSXTSegment -Id "sddc-cgw-network-4"
#>
Param (
[Parameter(Mandatory=$True)]$Id,
[Switch]$Troubleshoot
)
If (-Not $global:nsxtProxyConnection) { Write-error "No NSX-T Proxy Connection found, please use Connect-NSXTProxy" } Else {
$method = "DELETE"
$deleteSegmentsURL = $global:nsxtProxyConnection.Server + "/policy/api/v1/infra/networks/cgw/segments/$Id"
if($Troubleshoot) {
Write-Host -ForegroundColor cyan "`n[DEBUG] - $method`n$deleteSegmentsURL`n"
}
try {
if($PSVersionTable.PSEdition -eq "Core") {
$requests = Invoke-WebRequest -Uri $deleteSegmentsURL -Method $method -Headers $global:nsxtProxyConnection.headers -SkipCertificateCheck
} else {
$requests = Invoke-WebRequest -Uri $deleteSegmentsURL -Method $method -Headers $global:nsxtProxyConnection.headers
}
} catch {
Write-Host -ForegroundColor Red "`nThe NSX-T Proxy session is no longer valid, please re-run the Connect-NSXTProxy cmdlet to retrieve a new token`n"
break
}
if($requests.StatusCode -eq 200) {
Write-Host "Succesfully removed NSX-T Segment $Name"
} else {
Write-Error "Failed to remove NSX-T Segments"
}
}
}
Function Get-NSXTFirewall {
<#
.NOTES
===========================================================================
Created by: William Lam
Date: 09/11/2018
Organization: VMware
Blog: http://www.virtuallyghetto.com
Twitter: @lamw
===========================================================================
.SYNOPSIS
Returns all NSX-T Firewall Rules on MGW or CGW
.DESCRIPTION
This cmdlet retrieves all NSX-T Firewall Rules on MGW or CGW
.EXAMPLE
Get-NSXTFirewall -GatewayType MGW
.EXAMPLE
Get-NSXTFirewall -GatewayType MGW -Name "Test"
#>
param(
[Parameter(Mandatory=$false)][String]$Name,
[Parameter(Mandatory=$true)][ValidateSet("MGW","CGW")][String]$GatewayType,
[Switch]$Troubleshoot
)
If (-Not $global:nsxtProxyConnection) { Write-error "No NSX-T Proxy Connection found, please use Connect-NSXTProxy" } Else {
$method = "GET"
$edgeFirewallURL = $global:nsxtProxyConnection.Server + "/policy/api/v1/infra/domains/$($GatewayType.toLower())/edge-communication-maps/default"
if($Troubleshoot) {
Write-Host -ForegroundColor cyan "`n[DEBUG] - $method`n$edgeFirewallURL`n"
}
try {
if($PSVersionTable.PSEdition -eq "Core") {
$requests = Invoke-WebRequest -Uri $edgeFirewallURL -Method $method -Headers $global:nsxtProxyConnection.headers -SkipCertificateCheck
} else {
$requests = Invoke-WebRequest -Uri $edgeFirewallURL -Method $method -Headers $global:nsxtProxyConnection.headers
}
} catch {
Write-Host -ForegroundColor Red "`nThe NSX-T Proxy session is no longer valid, please re-run the Connect-NSXTProxy cmdlet to retrieve a new token`n"
break
}
if($requests.StatusCode -eq 200) {
$rules = ($requests.Content | ConvertFrom-Json).communication_entries
if ($PSBoundParameters.ContainsKey("Name")){
$rules = $rules | where {$_.display_name -eq $Name}
}
$results = @()
foreach ($rule in $rules | Sort-Object -Property sequence_number) {
$sourceGroups = $rule.source_groups
$source = @()
foreach ($sourceGroup in $sourceGroups) {
if($sourceGroup -eq "ANY") {
$source += $sourceGroup
break
} else {
$sourceGroupURL = $global:nsxtProxyConnection.Server + "/policy/api/v1" + $sourceGroup
if($Troubleshoot) {
Write-Host -ForegroundColor cyan "`n[DEBUG] - $method`n$sourceGroupURL`n"
}
try {
$requests = Invoke-WebRequest -Uri $sourceGroupURL -Method $method -Headers $global:nsxtProxyConnection.headers -SkipCertificateCheck
} catch {
Write-Host -ForegroundColor Red "`nThe NSX-T Proxy session is no longer valid, please re-run the Connect-NSXTProxy cmdlet to retrieve a new token`n"
break
}
$group = ($requests.Content | ConvertFrom-Json)
$source += $group.display_name
}
}
$destinationGroups = $rule.destination_groups
$destination = @()
foreach ($destinationGroup in $destinationGroups) {
if($destinationGroup -eq "ANY") {
$destination += $destinationGroup
break
} else {
$destionationGroupURL = $global:nsxtProxyConnection.Server + "/policy/api/v1" + $destinationGroup
if($Troubleshoot) {
Write-Host -ForegroundColor cyan "`n[DEBUG] - $method`n$destionationGroupURL`n"
}
try {
$requests = Invoke-WebRequest -Uri $destionationGroupURL -Method $method -Headers $global:nsxtProxyConnection.headers -SkipCertificateCheck
} catch {
Write-Host -ForegroundColor Red "`nThe NSX-T Proxy session is no longer valid, please re-run the Connect-NSXTProxy cmdlet to retrieve a new token`n"
break
}
$group = ($requests.Content | ConvertFrom-Json)
$destination += $group.display_name
}
}
$serviceGroups = $rule.services
$service = @()
foreach ($serviceGroup in $serviceGroups) {
if($serviceGroup -eq "ANY") {
$service += $serviceGroup
break
} else {
$serviceGroupURL = $global:nsxtProxyConnection.Server + "/policy/api/v1" + $serviceGroup
if($Troubleshoot) {
Write-Host -ForegroundColor cyan "`n[DEBUG] - $method`n$serviceGroupURL`n"
}
try {
$requests = Invoke-WebRequest -Uri $serviceGroupURL -Method $method -Headers $global:nsxtProxyConnection.headers -SkipCertificateCheck
} catch {
Write-Host -ForegroundColor Red "`nThe NSX-T Proxy session is no longer valid, please re-run the Connect-NSXTProxy cmdlet to retrieve a new token`n"
break
}
$group = ($requests.Content | ConvertFrom-Json)
$service += $group.display_name
}
}
$tmp = [pscustomobject] @{
SequenceNumber = $rule.sequence_number;
Name = $rule.display_name;
ID = $rule.id;
Source = $source;
Destination = $destination;
Services = $service;
Action = $rule.action;
}
$results+=$tmp
}
$results
} else {
Write-Error "Failed to retrieve NSX-T Firewall Rules"
}
}
}
Function New-NSXTFirewall {
<#
.NOTES
===========================================================================
Created by: William Lam
Date: 09/11/2018
Organization: VMware
Blog: http://www.virtuallyghetto.com
Twitter: @lamw
===========================================================================
.SYNOPSIS
Creates a new NSX-T Firewall Rule on MGW or CGW
.DESCRIPTION
This cmdlet creates a new NSX-T Firewall Rule on MGW or CGW
.EXAMPLE
New-NSXTFirewall -GatewayType MGW -Name TEST -Id TEST -SourceGroupId ESXI -DestinationGroupId ANY -Service ANY -Logged $true -SequenceNumber 7 -Action ALLOW
#>
Param (
[Parameter(Mandatory=$True)]$Name,
[Parameter(Mandatory=$true)][ValidateSet("MGW","CGW")][String]$GatewayType,
[Parameter(Mandatory=$True)]$Id,
[Parameter(Mandatory=$True)]$SequenceNumber,
[Parameter(Mandatory=$True)]$SourceGroupId,
[Parameter(Mandatory=$True)]$DestinationGroupId,
[Parameter(Mandatory=$True)]$Service,
[Parameter(Mandatory=$True)][ValidateSet("ALLOW","DENY")]$Action,
[Parameter(Mandatory=$false)][Boolean]$Logged=$false,
[Switch]$Troubleshoot
)
If (-Not $global:nsxtProxyConnection) { Write-error "No NSX-T Proxy Connection found, please use Connect-NSXTProxy" } Else {
if($DestinationGroupId -eq "ANY") {
$destinationGroups = $DestinationGroupId
} else {
$destinationGroups = "/infra/domains/$($GatewayType.toLower())/groups/$DestinationGroupId"
}
$sourceGroups = @()
foreach ($group in $SourceGroupId) {
$tmp = "/infra/domains/$($GatewayType.toLower())/groups/$group"
$sourceGroups+= $tmp
}
$services = @()
foreach ($serviceName in $Service) {
if($serviceName -eq "ANY") {
$tmp = "ANY"
} else {
$tmp = "/infra/services/$serviceName"
}
$services+=$tmp
}
$payload = @{
display_name = $Name;
resource_type = "CommunicationEntry";
id = $Id;
sequence_number = $SequenceNumber;
destination_groups = @($destinationGroups);
source_groups = $sourceGroups;
logged = $Logged;
scope = @("/infra/labels/$($GatewayType.toLower())");
services = $services;
action = $Action;
}
$body = $payload | ConvertTo-Json -depth 5
$method = "PUT"
$newFirewallURL = $global:nsxtProxyConnection.Server + "/policy/api/v1/infra/domains/$($GatewayType.toLower())/edge-communication-maps/default/communication-entries/$Id"
if($Troubleshoot) {
Write-Host -ForegroundColor cyan "`n[DEBUG] - $method`n$newFirewallURL`n"
Write-Host -ForegroundColor cyan "[DEBUG]`n$body`n"
}
try {
if($PSVersionTable.PSEdition -eq "Core") {
$requests = Invoke-WebRequest -Uri $newFirewallURL -Body $body -Method $method -Headers $global:nsxtProxyConnection.headers -SkipCertificateCheck
} else {
$requests = Invoke-WebRequest -Uri $newFirewallURL -Body $body -Method $method -Headers $global:nsxtProxyConnection.headers
}
} catch {
Write-Host -ForegroundColor Red "`nThe NSX-T Proxy session is no longer valid, please re-run the Connect-NSXTProxy cmdlet to retrieve a new token`n"
break
}
if($requests.StatusCode -eq 200) {
Write-Host "Succesfully created new NSX-T Firewall Rule $Name"
($requests.Content | ConvertFrom-Json) | select display_name, id
} else {
Write-Error "Failed to create new NSX-T Firewall Rule"
}
}
}
Function Remove-NSXTFirewall {
<#
.NOTES
===========================================================================
Created by: William Lam
Date: 09/11/2018
Organization: VMware
Blog: http://www.virtuallyghetto.com
Twitter: @lamw
===========================================================================
.SYNOPSIS
Removes an NSX-T Firewall Rule on MGW or CGW
.DESCRIPTION
This cmdlet removes an NSX-T Firewall Rule on MGW or CGW
.EXAMPLE
Remove-NSXTFirewall -Id TEST -GatewayType MGW -Troubleshoot
#>
Param (
[Parameter(Mandatory=$True)]$Id,
[Parameter(Mandatory=$true)][ValidateSet("MGW","CGW")][String]$GatewayType,
[Switch]$Troubleshoot
)
If (-Not $global:nsxtProxyConnection) { Write-error "No NSX-T Proxy Connection found, please use Connect-NSXTProxy" } Else {
$method = "DELETE"
$deleteGgroupURL = $global:nsxtProxyConnection.Server + "/policy/api/v1/infra/domains/$($GatewayType.toLower())/edge-communication-maps/default/communication-entries/$Id"
if($Troubleshoot) {
Write-Host -ForegroundColor cyan "`n[DEBUG] - $method`n$deleteGgroupURL`n"
}
try {
if($PSVersionTable.PSEdition -eq "Core") {
$requests = Invoke-WebRequest -Uri $deleteGgroupURL -Method $method -Headers $global:nsxtProxyConnection.headers -SkipCertificateCheck
} else {
$requests = Invoke-WebRequest -Uri $deleteGgroupURL -Method $method -Headers $global:nsxtProxyConnection.headers
}
} catch {
Write-Host -ForegroundColor Red "`nThe NSX-T Proxy session is no longer valid, please re-run the Connect-NSXTProxy cmdlet to retrieve a new token`n"
break
}
if($requests.StatusCode -eq 200) {
Write-Host "Succesfully removed NSX-T Firewall Rule $Name"
} else {
Write-Error "Failed to create new NSX-T Firewall Rule"
}
}
}
Function Get-NSXTGroup {
<#
.NOTES
===========================================================================
Created by: William Lam
Date: 09/11/2018
Organization: VMware
Blog: http://www.virtuallyghetto.com
Twitter: @lamw
===========================================================================
.SYNOPSIS
Returns all NSX-T Groups for MGW or CGW
.DESCRIPTION
This cmdlet retrieves all NSX-T Groups for MGW or CGW
.EXAMPLE
Get-NSXTGroup -GatewayType MGW
.EXAMPLE
Get-NSXTGroup -GatewayType MGW -Name "Test"
#>
param(
[Parameter(Mandatory=$false)][String]$Name,
[Parameter(Mandatory=$true)][ValidateSet("MGW","CGW")][String]$GatewayType,
[Switch]$Troubleshoot
)
If (-Not $global:nsxtProxyConnection) { Write-error "No NSX-T Proxy Connection found, please use Connect-NSXTProxy" } Else {
$method = "GET"
$edgeFirewallGroupsURL = $global:nsxtProxyConnection.Server + "/policy/api/v1/infra/domains/$($GatewayType.toLower())/groups"
if($Troubleshoot) {
Write-Host -ForegroundColor cyan "`n[DEBUG] - $method`n$edgeFirewallGroupsURL`n"
}
try {
if($PSVersionTable.PSEdition -eq "Core") {
$requests = Invoke-WebRequest -Uri $edgeFirewallGroupsURL -Method $method -Headers $global:nsxtProxyConnection.headers -SkipCertificateCheck
} else {
$requests = Invoke-WebRequest -Uri $edgeFirewallGroupsURL -Method $method -Headers $global:nsxtProxyConnection.headers
}
} catch {
Write-Host -ForegroundColor Red "`nThe NSX-T Proxy session is no longer valid, please re-run the Connect-NSXTProxy cmdlet to retrieve a new token`n"
break
}
if($requests.StatusCode -eq 200) {
$groups = ($requests.Content | ConvertFrom-Json).results
if ($PSBoundParameters.ContainsKey("Name")){
$groups = $groups | where {$_.display_name -eq $Name}
}
$results = @()
foreach ($group in $groups) {
if($group.tags.tag -eq $null) {
$groupType = "USER_DEFINED"
} else { $groupType = $group.tags.tag }
$members = @()
foreach ($member in $group.expression) {
if($member.ip_addresses) {
$members += $member.ip_addresses
} else {
if($member.resource_type -eq "Condition") {
$members += $member.value
}
}
}
$tmp = [pscustomobject] @{
Name = $group.display_name;
ID = $group.id;
Type = $groupType;
Members = $members;
}
$results+=$tmp
}
$results
} else {
Write-Error "Failed to retrieve NSX-T Groups"
}
}
}
Function New-NSXTGroup {
<#
.NOTES
===========================================================================
Created by: William Lam
Date: 09/11/2018
Organization: VMware
Blog: http://www.virtuallyghetto.com
Twitter: @lamw
===========================================================================
.SYNOPSIS
Creates a new NSX-T Group on MGW or CGW
.DESCRIPTION
This cmdlet creates a new NSX-T Firewall Rule on MGW or CGW
.EXAMPLE
New-NSXTGroup -GatewayType MGW -Name Foo -IPAddress @("172.31.0.0/24")
#>
Param (
[Parameter(Mandatory=$True)]$Name,
[Parameter(Mandatory=$true)][ValidateSet("MGW","CGW")][String]$GatewayType,
[Parameter(Mandatory=$True)][String[]]$IPAddress,
[Switch]$Troubleshoot
)
If (-Not $global:nsxtProxyConnection) { Write-error "No NSX-T Proxy Connection found, please use Connect-NSXTProxy" } Else {
$expression = @{
resource_type = "IPAddressExpression";
ip_addresses = $IPAddress;
}
$payload = @{
display_name = $Name;
expression = @($expression);
}
$body = $payload | ConvertTo-Json -depth 5
$method = "PUT"
$newGroupURL = $global:nsxtProxyConnection.Server + "/policy/api/v1/infra/domains/$($GatewayType.toLower())/groups/$Name"
if($Troubleshoot) {
Write-Host -ForegroundColor cyan "`n[DEBUG] - $method`n$newGroupURL`n"
Write-Host -ForegroundColor cyan "[DEBUG]`n$body`n"
}
try {
if($PSVersionTable.PSEdition -eq "Core") {
$requests = Invoke-WebRequest -Uri $newGroupURL -Body $body -Method $method -Headers $global:nsxtProxyConnection.headers -SkipCertificateCheck
} else {
$requests = Invoke-WebRequest -Uri $newGroupURL -Body $body -Method $method -Headers $global:nsxtProxyConnection.headers
}
} catch {
Write-Host -ForegroundColor Red "`nThe NSX-T Proxy session is no longer valid, please re-run the Connect-NSXTProxy cmdlet to retrieve a new token`n"
break
}
if($requests.StatusCode -eq 200) {
Write-Host "Succesfully created new NSX-T Group $Name"
($requests.Content | ConvertFrom-Json) | select display_name, id
} else {
Write-Error "Failed to create new NSX-T Group"
}
}
}
Function Remove-NSXTGroup {
<#
.NOTES
===========================================================================
Created by: William Lam
Date: 09/11/2018
Organization: VMware
Blog: http://www.virtuallyghetto.com
Twitter: @lamw
===========================================================================
.SYNOPSIS
Removes an NSX-T Group
.DESCRIPTION
This cmdlet removes an NSX-T Group
.EXAMPLE
Remove-NSXTGroup -Id Foo -GatewayType MGW -Troubleshoot
#>
Param (
[Parameter(Mandatory=$True)]$Id,
[Parameter(Mandatory=$true)][ValidateSet("MGW","CGW")][String]$GatewayType,
[Switch]$Troubleshoot
)
If (-Not $global:nsxtProxyConnection) { Write-error "No NSX-T Proxy Connection found, please use Connect-NSXTProxy" } Else {
$method = "DELETE"
$deleteGgroupURL = $global:nsxtProxyConnection.Server + "/policy/api/v1/infra/domains/$($GatewayType.toLower())/groups/$Id"
if($Troubleshoot) {
Write-Host -ForegroundColor cyan "`n[DEBUG] - $method`n$deleteGgroupURL`n"
}
try {
if($PSVersionTable.PSEdition -eq "Core") {
$requests = Invoke-WebRequest -Uri $deleteGgroupURL -Method $method -Headers $global:nsxtProxyConnection.headers -SkipCertificateCheck
} else {
$requests = Invoke-WebRequest -Uri $deleteGgroupURL -Method $method -Headers $global:nsxtProxyConnection.headers
}
} catch {
Write-Host -ForegroundColor Red "`nThe NSX-T Proxy session is no longer valid, please re-run the Connect-NSXTProxy cmdlet to retrieve a new token`n"
break
}
if($requests.StatusCode -eq 200) {
Write-Host "Succesfully removed NSX-T Group $Name"
} else {
Write-Error "Failed to create new NSX-T Group"
}
}
}
Function Get-NSXTService {
<#
.NOTES
===========================================================================
Created by: William Lam
Date: 09/11/2018
Organization: VMware
Blog: http://www.virtuallyghetto.com
Twitter: @lamw
===========================================================================
.SYNOPSIS
Returns all NSX-T Services
.DESCRIPTION
This cmdlet retrieves all NSX-T Services
.EXAMPLE
Get-NSXTService
.EXAMPLE
Get-NSXTService -Name "WINS"
#>
param(
[Parameter(Mandatory=$false)][String]$Name,
[Switch]$Troubleshoot
)
If (-Not $global:nsxtProxyConnection) { Write-error "No NSX-T Proxy Connection found, please use Connect-NSXTProxy" } Else {
$method = "GET"
$serviceGroupsURL = $global:nsxtProxyConnection.Server + "/policy/api/v1/infra/services"
if($Troubleshoot) {
Write-Host -ForegroundColor cyan "`n[DEBUG] - $method`n$serviceGroupsURL`n"
}
try {
if($PSVersionTable.PSEdition -eq "Core") {
$requests = Invoke-WebRequest -Uri $serviceGroupsURL -Method $method -Headers $global:nsxtProxyConnection.headers -SkipCertificateCheck
} else {
$requests = Invoke-WebRequest -Uri $serviceGroupsURL -Method $method -Headers $global:nsxtProxyConnection.headers
}
} catch {
Write-Host -ForegroundColor Red "`nThe NSX-T Proxy session is no longer valid, please re-run the Connect-NSXTProxy cmdlet to retrieve a new token`n"
break
}
if($requests.StatusCode -eq 200) {
$services = ($requests.Content | ConvertFrom-Json).results
if ($PSBoundParameters.ContainsKey("Name")){
$services = $services | where {$_.display_name -eq $Name}
}
$results = @()
foreach ($service in $services | Sort-Object -Propert display_name) {
$serviceEntry = $service.service_entries
$serviceProtocol = $serviceEntry.l4_protocol
$serviceSourcePorts = $serviceEntry.source_ports
$serviceDestinationPorts = $serviceEntry.destination_ports
$tmp = [pscustomobject] @{
Name = $service.display_name;
Id = $service.id;
Protocol = $serviceProtocol;
Source = $serviceSourcePorts;
Destination = $serviceDestinationPorts;
}
$results += $tmp
}
$results
} else {
Write-Error "Failed to retrieve NSX-T Services"
}
}
}
Function New-NSXTService {
<#
.NOTES
===========================================================================
Created by: William Lam
Date: 09/11/2018
Organization: VMware
Blog: http://www.virtuallyghetto.com
Twitter: @lamw
===========================================================================
.SYNOPSIS
Creates a new NSX-T Service
.DESCRIPTION
This cmdlet creates a new NSX-T Service
.EXAMPLE
New-NSXTService -Name "MyHTTP2" -Protocol TCP -DestinationPorts @("8080","8081")
#>
Param (
[Parameter(Mandatory=$True)]$Name,
[Parameter(Mandatory=$True)][String[]]$DestinationPorts,
[Parameter(Mandatory=$True)][ValidateSet("TCP","UDP")][String]$Protocol,
[Switch]$Troubleshoot
)
If (-Not $global:nsxtProxyConnection) { Write-error "No NSX-T Proxy Connection found, please use Connect-NSXTProxy" } Else {
$serviceEntry = @()
$entry = @{
display_name = $name + "-$destinationPort"
resource_type = "L4PortSetServiceEntry";
destination_ports = @($DestinationPorts);
l4_protocol = $Protocol;
}
$serviceEntry+=$entry
$payload = @{
display_name = $Name;
service_entries = $serviceEntry;
}
$body = $payload | ConvertTo-Json -depth 5
$method = "PUT"
$newServiceURL = $global:nsxtProxyConnection.Server + "/policy/api/v1/infra/services/$Name"
if($Troubleshoot) {
Write-Host -ForegroundColor cyan "`n[DEBUG] - $method`n$newServiceURL`n"
Write-Host -ForegroundColor cyan "[DEBUG]`n$body`n"
}
try {
if($PSVersionTable.PSEdition -eq "Core") {
$requests = Invoke-WebRequest -Uri $newServiceURL -Body $body -Method $method -Headers $global:nsxtProxyConnection.headers -SkipCertificateCheck
} else {
$requests = Invoke-WebRequest -Uri $newServiceURL -Body $body -Method $method -Headers $global:nsxtProxyConnection.headers
}
} catch {
Write-Host -ForegroundColor Red "`nThe NSX-T Proxy session is no longer valid, please re-run the Connect-NSXTProxy cmdlet to retrieve a new token`n"
break
}
if($requests.StatusCode -eq 200) {
Write-Host "Succesfully created new NSX-T Service $Name"
($requests.Content | ConvertFrom-Json) | select display_name, id
} else {
Write-Error "Failed to create new NSX-T Service"
}
}
}

Binary file not shown.

File diff suppressed because it is too large Load Diff

View File

@@ -2,6 +2,31 @@ Prerequisites/Steps to use this module:
1. This module only works for vSphere products that support VM Encryption. E.g. vSphere 6.5 and later.
2. All the functions in this module only work for KMIP Servers.
3. Install the latest version of Powershell and PowerCLI(6.5).
3. Install the latest version of Powershell and PowerCLI.
4. Import this module by running: Import-Module -Name "location of this module"
5. Get-Command -Module "This module Name" to list all available functions.
5. Get-Command -Module "This module Name" to list all available functions.
Note:
Deprecating the below functions related to KMServer and KMSCluster from VMware.VMEncryption and using instead the ones from VMware.VimAutomation.Storage,
1, VMware.VMEncryption\Get-DefaultKMSCluster, use instead
VMware.VimAutomation.Storage\Get-KmsCluster|where {$_.UseAsDefaultKeyProvider}|foreach {$_.id}
2, VMware.VMEncryption\Get-KMSCluster, use instead
VMware.VimAutomation.Storage\Get-KmsCluster|select id
3, VMware.VMEncryption\Get-KMSClusterInfo, use instead
VMware.VimAutomation.Storage\Get-KmsCluster|foreach {$_.extensiondata}
4, VMware.VMEncryption\Get-KMServerInfo, use instead
VMware.VimAutomation.Storage\Get-KeyManagementServer|foreach {$_.extensiondata}
5, VMware.VMEncryption\New-KMServer, use instead
VMware.VimAutomation.Storage\Add-KeyManagementServer
6, VMware.VMEncryption\Remove-KMServer, use instead
VMware.VimAutomation.Storage\Remove-KeyManagementServer
7, VMware.VMEncryption\Set-DefaultKMSCluster, use instead
VMware.VimAutomation.Storage\Set-KmsCluster -UseAsDefaultKeyProvider

View File

@@ -1,5 +1,5 @@
# Script Module : VMware.VMEncryption
# Version : 1.0
# Version : 1.2
# Copyright © 2016 VMware, Inc. All Rights Reserved.
@@ -56,8 +56,13 @@ New-VIProperty -Name EncryptionKeyId -ObjectType VirtualMachine -Value {
New-VIProperty -Name Locked -ObjectType VirtualMachine -Value {
Param ($VM)
($vm.extensiondata.Runtime.ConnectionState -eq "invalid") -and ($vm.extensiondata.Config.KeyId)
} -BasedOnExtensionProperty 'Runtime.ConnectionState','Config.KeyId' -Force | Out-Null
if ($vm.ExtensionData.Runtime.CryptoState) {
$vm.ExtensionData.Runtime.CryptoState -eq "locked"
}
else {
($vm.extensiondata.Runtime.ConnectionState -eq "invalid") -and ($vm.extensiondata.Config.KeyId)
}
} -BasedOnExtensionProperty 'Runtime.CryptoState', 'Runtime.ConnectionState','Config.KeyId' -Force | Out-Null
New-VIProperty -Name vMotionEncryption -ObjectType VirtualMachine -Value {
Param ($VM)
@@ -83,6 +88,13 @@ New-VIProperty -Name EncryptionKeyId -ObjectType HardDisk -Value {
}
} -BasedOnExtensionProperty 'Backing.KeyId' -Force | Out-Null
New-VIProperty -Name KMSserver -ObjectType VMHost -Value {
Param ($VMHost)
if ($VMHost.CryptoSafe) {
$VMHost.ExtensionData.Runtime.CryptoKeyId.ProviderId.Id
}
} -BasedOnExtensionProperty 'Runtime.CryptoKeyId.ProviderId.Id' -Force | Out-Null
Function Enable-VMHostCryptoSafe {
<#
.SYNOPSIS
@@ -106,13 +118,6 @@ Function Enable-VMHostCryptoSafe {
.NOTES
Author : Baoyin Qiao.
Author email : bqiao@vmware.com
Version : 1.0
==========Tested Against Environment==========
VMware vSphere Hypervisor(ESXi) Version : 6.5
VMware vCenter Server Version : 6.5
PowerCLI Version : PowerCLI 6.5
PowerShell Version : 3.0
#>
[CmdLetBinding()]
@@ -174,13 +179,6 @@ Function Set-VMHostCryptoKey {
.NOTES
Author : Baoyin Qiao.
Author email : bqiao@vmware.com
Version : 1.0
==========Tested Against Environment==========
VMware vSphere Hypervisor(ESXi) Version : 6.5
VMware vCenter Server Version : 6.5
PowerCLI Version : PowerCLI 6.5
PowerShell Version : 3.0
#>
[CmdLetBinding()]
@@ -259,13 +257,6 @@ Function Set-vMotionEncryptionConfig {
.NOTES
Author : Brian Graf, Carrie Yang.
Author email : grafb@vmware.com, yangm@vmware.com
Version : 1.0
==========Tested Against Environment==========
VMware vSphere Hypervisor(ESXi) Version : 6.5
VMware vCenter Server Version : 6.5
PowerCLI Version : PowerCLI 6.5
PowerShell Version : 3.0
#>
[CmdLetBinding()]
@@ -341,13 +332,6 @@ Function Enable-VMEncryption {
.NOTES
Author : Baoyin Qiao.
Author email : bqiao@vmware.com
Version : 1.0
==========Tested Against Environment==========
VMware vSphere Hypervisor(ESXi) Version : 6.5
VMware vCenter Server Version : 6.5
PowerCLI Version : PowerCLI 6.5
PowerShell Version : 3.0
#>
[CmdLetBinding()]
@@ -501,13 +485,6 @@ Function Enable-VMDiskEncryption {
.NOTES
Author : Baoyin Qiao.
Author email : bqiao@vmware.com
Version : 1.0
==========Tested Against Environment==========
VMware vSphere Hypervisor(ESXi) Version : 6.5
VMware vCenter Server Version : 6.5
PowerCLI Version : PowerCLI 6.5
PowerShell Version : 3.0
#>
[CmdLetBinding()]
@@ -653,13 +630,6 @@ Function Disable-VMEncryption {
.NOTES
Author : Carrie Yang.
Author email : yangm@vmware.com
Version : 1.0
==========Tested Against Environment==========
VMware vSphere Hypervisor(ESXi) Version : 6.5
VMware vCenter Server Version : 6.5
PowerCLI Version : PowerCLI 6.5
PowerShell Version : 3.0
#>
[CmdLetBinding()]
@@ -749,13 +719,6 @@ Function Disable-VMDiskEncryption {
.NOTES
Author : Carrie Yang.
Author email : yangm@vmware.com
Version : 1.0
==========Tested Against Environment==========
VMware vSphere Hypervisor(ESXi) Version : 6.5
VMware vCenter Server Version : 6.5
PowerCLI Version : PowerCLI 6.5
PowerShell Version : 3.0
#>
[CmdLetBinding()]
@@ -875,7 +838,7 @@ Function Set-VMEncryptionKey {
C:\PS>$VM|Set-VMEncryptionKey -KMSClusterId $KMSCluster.Id -Deep
Deep rekeys the VM Home and all its disks using a new key.
The key is generted from the KMS whose clusterId is $KMSCluster.Id.
The key is generated from the KMS whose clusterId is $KMSCluster.Id.
.NOTES
This cmdlet assumes there is already a KMS in vCenter Server. If VM is not encrypted, the cmdlet quits.
@@ -884,13 +847,6 @@ Function Set-VMEncryptionKey {
.NOTES
Author : Carrie Yang.
Author email : yangm@vmware.com
Version : 1.0
==========Tested Against Environment==========
VMware vSphere Hypervisor(ESXi) Version : 6.5
VMware vCenter Server Version : 6.5
PowerCLI Version : PowerCLI 6.5
PowerShell Version : 3.0
#>
[CmdLetBinding()]
@@ -1027,10 +983,10 @@ Function Set-VMDiskEncryptionKey {
C:\PS>$KMSCluster = Get-KMSCluster | select -last 1
C:\PS>$VM = Get-VM -Name win2012
C:\PS>$HardDisk = get-vm $vm|Get-HardDisk
C:\PS>$HardDisk|$Set-VMEncryptionKey -VM $VM -KMSClusterId $KMSCluster.Id -Deep
C:\PS>$HardDisk| Set-VMDiskEncryptionKey -VM $VM -KMSClusterId $KMSCluster.Id -Deep
Deep rekeys all the disks of the $VM using a new key.
The key is generted from the KMS whose clusterId is $KMSCluster.Id.
The key is generated from the KMS whose clusterId is $KMSCluster.Id.
.NOTES
This cmdlet assumes there is already a KMS in vCenter Server.
@@ -1040,13 +996,6 @@ Function Set-VMDiskEncryptionKey {
.NOTES
Author : Carrie Yang.
Author email : yangm@vmware.com
Version : 1.0
==========Tested Against Environment==========
VMware vSphere Hypervisor(ESXi) Version : 6.5
VMware vCenter Server Version : 6.5
PowerCLI Version : PowerCLI 6.5
PowerShell Version : 3.0
#>
[CmdLetBinding()]
@@ -1163,13 +1112,6 @@ Function Get-VMEncryptionInfo {
.NOTES
Author : Carrie Yang.
Author email : yangm@vmware.com
Version : 1.0
==========Tested Against Environment==========
VMware vSphere Hypervisor(ESXi) Version : 6.5
VMware vCenter Server Version : 6.5
PowerCLI Version : PowerCLI 6.5
PowerShell Version : 3.0
#>
[CmdLetBinding()]
@@ -1262,13 +1204,6 @@ Function Get-EntityByCryptoKey {
.NOTES
Author : Baoyin Qiao.
Author email : bqiao@vmware.com
Version : 1.0
==========Tested Against Environment==========
VMware vSphere Hypervisor(ESXi) Version : 6.5
VMware vCenter Server Version : 6.5
PowerCLI Version : PowerCLI 6.5
PowerShell Version : 3.0
#>
[CmdLetBinding()]
@@ -1387,13 +1322,6 @@ Function New-KMServer {
.NOTES
Author : Baoyin Qiao.
Author email : bqiao@vmware.com
Version : 1.0
==========Tested Against Environment==========
VMware vSphere Hypervisor(ESXi) Version : 6.5
VMware vCenter Server Version : 6.5
PowerCLI Version : PowerCLI 6.5
PowerShell Version : 3.0
#>
[CmdLetBinding()]
@@ -1428,6 +1356,7 @@ Function New-KMServer {
)
Begin {
write-warning "This cmdlet is deprecated and will be removed in future release. Use VMware.VimAutomation.Storage\Add-KeyManagementServer instead"
# Confirm the connected VIServer is vCenter Server
ConfirmIsVCenter
@@ -1546,13 +1475,6 @@ Function Remove-KMServer {
.NOTES
Author : Baoyin Qiao.
Author email : bqiao@vmware.com
Version : 1.0
==========Tested Against Environment==========
VMware vSphere Hypervisor(ESXi) Version : 6.5
VMware vCenter Server Version : 6.5
PowerCLI Version : PowerCLI 6.5
PowerShell Version : 3.0
#>
[CmdLetBinding()]
@@ -1566,6 +1488,7 @@ Function Remove-KMServer {
)
Begin {
write-warning "This cmdlet is deprecated and will be removed in future release. Use VMware.VimAutomation.Storage\Remove-KeyManagementServer instead"
# Confirm the connected VIServer is vCenter Server
ConfirmIsVCenter
@@ -1623,15 +1546,9 @@ Function Get-KMSCluster {
.NOTES
Author : Baoyin Qiao.
Author email : bqiao@vmware.com
Version : 1.0
==========Tested Against Environment==========
VMware vSphere Hypervisor(ESXi) Version : 6.5
VMware vCenter Server Version : 6.5
PowerCLI Version : PowerCLI 6.5
PowerShell Version : 3.0
#>
write-warning "This cmdlet is deprecated and will be removed in future release. Use VMware.VimAutomation.Storage\Get-KmsCluster instead"
# Confirm the connected VIServer is vCenter Server
ConfirmIsVCenter
@@ -1661,14 +1578,6 @@ Function Get-KMSClusterInfo {
.NOTES
Author : Baoyin Qiao.
Author email : bqiao@vmware.com
Version : 1.0
==========Tested Against Environment==========
VMware vSphere Hypervisor(ESXi) Version : 6.5
VMware vCenter Server Version : 6.5
PowerCLI Version : PowerCLI 6.5
PowerShell Version : 3.0
#>
[CmdLetBinding()]
@@ -1679,6 +1588,7 @@ Function Get-KMSClusterInfo {
)
Begin {
write-warning "This cmdlet is deprecated and will be removed in future release. Use VMware.VimAutomation.Storage\Get-KmsCluster instead"
# Confirm the connected VIServer is vCenter Server
ConfirmIsVCenter
@@ -1714,13 +1624,6 @@ Function Get-KMServerInfo {
.NOTES
Author : Baoyin Qiao.
Author email : bqiao@vmware.com
Version : 1.0
==========Tested Against Environment==========
VMware vSphere Hypervisor(ESXi) Version : 6.5
VMware vCenter Server Version : 6.5
PowerCLI Version : PowerCLI 6.5
PowerShell Version : 3.0
#>
[CmdLetBinding()]
@@ -1731,6 +1634,7 @@ Function Get-KMServerInfo {
)
Begin {
write-warning "This cmdlet is deprecated and will be removed in future release. Use VMware.VimAutomation.Storage\Get-KeyManagementServer instead"
# Confirm the connected VIServer is vCenter Server
ConfirmIsVCenter
@@ -1775,13 +1679,6 @@ Function Get-KMServerStatus {
.NOTES
Author : Baoyin Qiao.
Author email : bqiao@vmware.com
Version : 1.0
==========Tested Against Environment==========
VMware vSphere Hypervisor(ESXi) Version : 6.5
VMware vCenter Server Version : 6.5
PowerCLI Version : PowerCLI 6.5
PowerShell Version : 3.0
#>
[CmdLetBinding()]
@@ -1846,15 +1743,9 @@ Function Get-DefaultKMSCluster {
.NOTES
Author : Baoyin Qiao.
Author email : bqiao@vmware.com
Version : 1.0
==========Tested Against Environment==========
VMware vSphere Hypervisor(ESXi) Version : 6.5
VMware vCenter Server Version : 6.5
PowerCLI Version : PowerCLI 6.5
PowerShell Version : 3.0
#>
write-warning "This cmdlet is deprecated and will be removed in future release. Use VMware.VimAutomation.Storage\Get-KmsCluster instead"
# Confirm the connected VIServer is vCenter Server
ConfirmIsVCenter
@@ -1883,13 +1774,6 @@ Function Set-DefaultKMSCluster {
.NOTES
Author : Baoyin Qiao.
Author email : bqiao@vmware.com
Version : 1.0
==========Tested Against Environment==========
VMware vSphere Hypervisor(ESXi) Version : 6.5
VMware vCenter Server Version : 6.5
PowerCLI Version : PowerCLI 6.5
PowerShell Version : 3.0
#>
[CmdLetBinding()]
@@ -1899,6 +1783,7 @@ Function Set-DefaultKMSCluster {
[String] $KMSClusterId
)
write-warning "This cmdlet is deprecated and will be removed in future release. Use VMware.VimAutomation.Storage\Set-KmsCluster instead"
# Confirm the connected VIServer is vCenter Server
ConfirmIsVCenter
@@ -1910,6 +1795,353 @@ Function Set-DefaultKMSCluster {
$CM.MarkDefault($ProviderId)
}
Function Set-VMCryptoUnlock {
<#
.SYNOPSIS
This cmdlet unlocks a locked vm
.DESCRIPTION
This cmdlet unlocks a locked vm
.PARAMETER VM
Specifies the VM you want to unlock
.EXAMPLE
PS C:\> Get-VM |where {$_.locked}| Set-VMCryptoUnlock
Unlock all locked vms
.NOTES
Author : Fangying Zhang
Author email : fzhang@vmware.com
#>
[CmdLetBinding()]
param (
[Parameter(Mandatory=$True,ValueFromPipeline=$True,ValueFromPipelinebyPropertyName=$True)]
[VMware.VimAutomation.ViCore.Types.V1.Inventory.VirtualMachine[]]$VM
)
Begin {
# Confirm the connected VIServer is vCenter Server
ConfirmIsVCenter
}
Process {
foreach ($thisvm in $vm) {
if (!$thisvm.encrypted) {
write-warning "$thisvm is not encrypted, will skip $thisvm"
continue
}
if (!$thisvm.Locked) {
write-warning "$thisvm may not be locked!"
# $thisvm.locked could be false on old 6.5.0 build (bug 1931370), so do not skip $thisvm
}
write-verbose "try to CryptoUnlock $thisvm"
$thisvm.ExtensionData.CryptoUnlock()
}
}
}
Function Add-Vtpm {
<#
.SYNOPSIS
This cmdlet adds a Virtual TPM to the specified VM.
.DESCRIPTION
This cmdlet adds a Virtual TPM to the specified VM.
.PARAMETER VM
Specifies the VM you want to add Virtual TPM to.
.EXAMPLE
C:\PS>$vm1 = Get-VM -Name win2016
C:\PS>Add-Vtpm $vm1
Encrypts $vm1's VM home and adds Virtual TPM
.NOTES
If VM home is already encrypted, the cmdlet will add a Virtual TPM to the VM.
If VM home is not encrypted, VM home will be encrypted and Virtual TPM will be added.
.NOTES
Author : Chong Yeo.
Author email : cyeo@vmware.com
#>
[CmdLetBinding()]
param (
[Parameter(Mandatory=$True,ValueFromPipeline=$True,ValueFromPipelinebyPropertyName=$True)]
[VMware.VimAutomation.ViCore.Types.V1.Inventory.VirtualMachine] $VM
)
Begin {
# Confirm the connected VIServer is vCenter Server
ConfirmIsVCenter
}
Process {
$deviceChange = New-Object VMware.Vim.VirtualDeviceConfigSpec
$deviceChange.operation = "add"
$deviceChange.device = new-object VMware.Vim.VirtualTPM
$VMCfgSpec = New-Object VMware.Vim.VirtualMachineConfigSpec
$VMCfgSpec.DeviceChange = $deviceChange
return $VM.ExtensionData.ReconfigVM_task($VMCfgSpec)
}
}
Function Remove-Vtpm {
<#
.SYNOPSIS
This cmdlet removes a Virtual TPM from the specified VM.
.DESCRIPTION
This cmdlet removes a Virtual TPM from the specified VM.
.PARAMETER VM
Specifies the VM you want to remove Virtual TPM from.
.EXAMPLE
C:\PS>$vm1 = Get-VM -Name win2016
C:\PS>Remove-Vtpm $vm1
.EXAMPLE
C:\PS>Get-VM -Name win2016 |Remove-Vtpm
Remove Virtual TPM from VM named win2016
.NOTES
Removing VirtualTPM will render all encrypted data on this VM unrecoverable.
VM home encryption state will be returned to the original state before Virtual TPM is added
.NOTES
Author : Chong Yeo.
Author email : cyeo@vmware.com
#>
[CmdLetBinding(SupportsShouldProcess=$true, ConfirmImpact = "High")]
param (
[Parameter(Mandatory=$True,ValueFromPipeline=$True,ValueFromPipelinebyPropertyName=$True)]
[VMware.VimAutomation.ViCore.Types.V1.Inventory.VirtualMachine] $VM
)
Begin {
# Confirm the connected VIServer is vCenter Server
ConfirmIsVCenter
}
Process {
$message = "Removing Virtual TPM will render all encrypted data on this VM unrecoverable"
if ($PSCmdlet.ShouldProcess($message, $message + "`n Do you want to proceed", "WARNING")) {
$deviceChange = New-Object VMware.Vim.VirtualDeviceConfigSpec
$deviceChange.operation = "remove"
$deviceChange.device = $vtpm
$VMCfgSpec = New-Object VMware.Vim.VirtualMachineConfigSpec
$VMCfgSpec.DeviceChange = $deviceChange
return $VM.ExtensionData.ReconfigVM_task($VMCfgSpec)
}
}
}
Function Get-VtpmCsr {
<#
.SYNOPSIS
This cmdlet gets certficate signing requests(CSR) from Virtual TPM.
.DESCRIPTION
This cmdlet gets certficate signing requests(CSR) from Virtual TPM.
The CSR is a ComObject X509enrollment.CX509CertificateRequestPkcs10
.PARAMETER VM
Specifies the VM you want to get the CSRs Virtual TPM from.
.PARAMETER KeyType [RSA | ECC]
Specify that only get CSR with public key RSA algorithm.
If none is specified, both CSR will get returned
.EXAMPLE
C:\PS>$vm1 = Get-VM -Name win2016
C:\PS>Get-VtpmCsr $vm1 -KeyType RSA
.NOTES
Both RSA and ECC CSRs objects will be returned. If ECC or RSA is specified,
only the corresponding object will be returned
.NOTES
Author : Chong Yeo.
Author email : cyeo@vmware.com
#>
[CmdLetBinding()]
param (
[Parameter(Mandatory=$True,ValueFromPipeline=$True,ValueFromPipelinebyPropertyName=$True)]
[VMware.VimAutomation.ViCore.Types.V1.Inventory.VirtualMachine] $VM,
[Parameter(Mandatory=$False)]
[String]$KeyType
)
Begin {
# Confirm the connected VIServer is vCenter Server
ConfirmIsVCenter
}
process {
# Get vTPM from VM
$vtpm = $VM.ExtensionData.Config.Hardware.Device |Where {$_ -is [VMware.Vim.VirtualTPM]}
# Check if vTPM is already present
if (!$vtpm) {
Write-Error "$VM does not contains a Virtual TPM"
return
}
$CSRs = @()
foreach ($csrArray in $vtpm.EndorsementKeyCertificateSigningRequest) {
$csrString = [System.Convert]::ToBase64String($csrArray)
$csr = New-Object -ComObject X509enrollment.CX509CertificateRequestPkcs10
#decode a base64 string into a CSR object
$csr.InitializeDecode($csrString,6)
if ($keyType) {
if ($csr.PublicKey.Algorithm.FriendlyName -eq $KeyType){
return $csr
}
} else {
$CSRs += $csr
}
}
return $CSRs
}
}
Function Set-VtpmCert{
<#
.SYNOPSIS
This cmdlet replaces certificates of Virtual TPM in the specified VM.
.DESCRIPTION
This cmdlet replaces certificates to Virtual TPM in the specified VM.
.PARAMETER VM
Specifies the VM with Virtual TPM where you want to replace the certificates to.
.PARAMETER Cert
Specifies the certificate object (System.Security.Cryptography.X509Certificates.X509Certificate)
.EXAMPLE
C:\PS>$vm1 = Get-VM -Name win2016
C:\PS>Set-VtpmCert $vm1 $certObj
.EXAMPLE
C:\PS>Get-VM -Name win2016 | Set-VtpmCert $certObj
Replace the appropriate certificate specified
.NOTES
Only RSA or ECC certs will be overwritten
.NOTES
Author : Chong Yeo.
Author email : cyeo@vmware.com
#>
[CmdLetBinding()]
param (
[Parameter(Mandatory=$True,ValueFromPipeline=$True,ValueFromPipelinebyPropertyName=$True)]
[VMware.VimAutomation.ViCore.Types.V1.Inventory.VirtualMachine]$VM,
[Parameter(Mandatory=$True)]
[System.Security.Cryptography.X509Certificates.X509Certificate] $Cert
)
Begin {
# Confirm the connected VIServer is vCenter Server
ConfirmIsVCenter
}
process {
# Get vTPM from VM
$vtpm = $VM.ExtensionData.Config.Hardware.Device |Where {$_ -is [VMware.Vim.VirtualTPM]}
#check if vTPM is already present
if (!$vtpm) {
Write-Error "$VM does not contains a Virtual TPM"
return
}
$certOid = New-Object System.Security.Cryptography.Oid($Cert.GetKeyAlgorithm())
# Check which certificate to overwrite
$certLocation = GetKeyIndex $vtpm.EndorsementKeyCertificate $certOid.FriendlyName
if ($certLocation -eq -1) {
Write-Error "No Certificate with Matching Algorithm $($certOid.FriendlyName) found"
return
}
$vtpm.EndorsementKeyCertificate[$certLocation] = $cert.GetRawCertData()
$deviceChange = New-Object VMware.Vim.VirtualDeviceConfigSpec
$deviceChange.Operation = "edit"
$deviceChange.Device = $vtpm
$VMCfgSpec = New-Object VMware.Vim.VirtualMachineConfigSpec
$VMCfgSpec.DeviceChange = $deviceChange
return $VM.ExtensionData.ReconfigVM_task($VMCfgSpec)
}
}
Function Get-VtpmCert{
<#
.SYNOPSIS
This cmdlet gets certificates of Virtual TPM in the specified VM.
.DESCRIPTION
This cmdlet gets certificates of Virtual TPM in the specified VM.
.PARAMETER VM
Specifies the VM with Virtual TPM where you want to get the certificate from
.EXAMPLE
C:\PS>$vm1 = Get-VM -Name win2016
C:\PS>$certs = Get-VtpmCert $vm1
.NOTES
An array of certificate object (System.Security.Cryptography.X509Certificates.X509Certificate)
will be returned
.NOTES
Author : Chong Yeo.
Author email : cyeo@vmware.com
#>
[CmdLetBinding()]
param (
[Parameter(Mandatory=$True,ValueFromPipeline=$True,ValueFromPipelinebyPropertyName=$True)]
[VMware.VimAutomation.ViCore.Types.V1.Inventory.VirtualMachine] $VM
)
Begin {
# Confirm the connected VIServer is vCenter Server
ConfirmIsVCenter
}
Process {
# Get vTPM from VM
$vtpm = $VM.ExtensionData.Config.Hardware.Device |Where {$_ -is [VMware.Vim.VirtualTPM]}
# check if vTPM is already present
if (!$vtpm) {
Write-Error "$VM does not contain a Virtual TPM"
return
}
$certs = @()
$vtpm.EndorsementKeyCertificate|foreach {
$cert = New-Object System.Security.Cryptography.X509Certificates.X509Certificate
$cert.Import($_)
$certs += $cert
}
return $certs
}
}
Function ConfirmIsVCenter{
<#
.SYNOPSIS
@@ -2104,4 +2336,49 @@ Function GetCryptoManager {
}
}
Function GetKeyIndex{
<#
.SYNOPSIS
This cmdlet returns the index to the key with a matching algorithm as the KeyType parameter
.DESCRIPTION
This cmdlet returns the index to the key with a matching algorithm as the KeyType parameter
.PARAMETER Certs
Specifies the list of certificats. Expected format is byte[][]
.PARAMETER KeyType
Specifies the keytype to search for
.EXAMPLE
C:\PS>$keyIndex = GetKeyIndex $Certs RSA
C:\PS>$keyIndex = GetKeyIndex $Certs ECC
.NOTES
Author : Chong Yeo.
Author email : cyeo@vmware.com
#>
[CmdLetBinding()]
param (
[Parameter(Mandatory=$True)]
[byte[][]] $Certs,
[Parameter(Mandatory=$True)]
[String] $KeyType
)
process {
for ($i=0;$i -lt $Certs.Length; $i++) {
$cert = New-Object System.Security.Cryptography.X509Certificates.X509Certificate
$cert.Import($Certs.Get($i))
$certType = New-Object System.Security.Cryptography.Oid($cert.GetKeyAlgorithm())
if ( $certType.FriendlyName -eq $keyType) {
return $i
}
}
return -1
}
}
Export-ModuleMember *-*

View File

@@ -0,0 +1,82 @@
function Validate-ESXiPackages {
<#
.DESCRIPTION
Compares all ESXi Host VIBs within a vSphere with a reference Hosts.
.NOTES
File Name : Validate-ESXiPackages.ps1
Author : Markus Kraus
Version : 1.0
State : Ready
Tested Against Environment:
vSphere Version: 6.0 U2, 6.5 U1
PowerCLI Version: PowerCLI 10.0.0 build 7895300
PowerShell Version: 4.0
OS Version: Windows Server 2012 R2
.LINK
https://mycloudrevolution.com/
.EXAMPLE
Validate-ESXiPackages -Cluster (Get-Cluster) -RefernceHost (Get-VMHost | Select-Object -First 1)
.PARAMETER Cluster
vSphere Cluster to verify
.PARAMETER RefernceHost
The VIB Reference ESXi Host
#>
[CmdletBinding()]
param(
[Parameter(Mandatory=$True, ValueFromPipeline=$True, HelpMessage="vSphere Cluster to verify")]
[ValidateNotNullorEmpty()]
[VMware.VimAutomation.ViCore.Impl.V1.Inventory.ComputeResourceImpl] $Cluster,
[Parameter(Mandatory=$True, ValueFromPipeline=$false, HelpMessage="The VIB Reference ESXi Host")]
[ValidateNotNullorEmpty()]
[VMware.VimAutomation.ViCore.Impl.V1.Inventory.InventoryItemImpl] $RefernceHost
)
Process {
#region: Get reference VIBs
$EsxCli2 = Get-ESXCLI -VMHost $RefernceHost -V2
$RefernceVibList = $esxcli2.software.vib.list.invoke()
#endregion
#region: Compare reference VIBs
$MyView = @()
foreach ($VmHost in ($Cluster | Get-VMHost)) {
$EsxCli2 = Get-ESXCLI -VMHost $VmHost -V2
$VibList = $esxcli2.software.vib.list.invoke()
[Array]$VibDiff = Compare-Object -ReferenceObject $RefernceVibList.ID -DifferenceObject $VibList.ID
if($VibDiff.Count -gt 0) {
$VibDiffSideIndicator = @()
foreach ($Item in $VibDiff) {
$VibDiffSideIndicator += $($Item.SideIndicator + " " + $Item.InputObject)
}
}
else {
$VibDiffSideIndicator = $null
}
$Report = [PSCustomObject] @{
Host = $VmHost.Name
Version = $VmHost.Version
Build = $VmHost.Build
VibDiffCount = $VibDiff.Count
VibDiff = $VibDiff.InputObject
VibDiffSideIndicator = $VibDiffSideIndicator
}
$MyView += $Report
}
#region: Compare reference VIBs
$MyView
}
}

View File

@@ -0,0 +1,17 @@
# Fetch Cis Server hostname and credentials
.\CisConfig.ps1
Connect-rCisServer -Server $cisServer -User $cisUser -Password $cisPswd
# Get Tag information
Get-rCisTag
# Get Tag Category information
Get-rCisTagCategory
# Get Tag Assignment information
Get-rCisTagAssignment
Disconnect-rCisServer -Server $cisServer -Confirm:$false

View File

@@ -0,0 +1,14 @@
# Fetch Cis Server hostname and credentials
.\CisConfig.ps1
Connect-rCisServer -Server $cisServer -User $cisUser -Password $cisPswd
New-rCisTagCategory -Name MyCat1 -Cardinality Single -Description 'Test Tag Category' -EntityType 'VirtualMachine'
New-rCisTag -Name MyTag1 -Category MyCat1 -Description 'Test Tag'
$vm = Get-VM | Get-Random
New-rCisTagAssignment -Entity $vm -Tag MyTag1
Get-rCisTagAssignment -Tag MyTag1
Disconnect-rCisServer -Server $cisServer -Confirm:$false

View File

@@ -0,0 +1,11 @@
# Fetch Cis Server hostname and credentials
.\CisConfig.ps1
Connect-rCisServer -Server $cisServer -User $cisUser -Password $cisPswd
Get-rCisTag -Name MyTag1 | Set-rCisTag -Name MyNewTag1 -Description 'Name changed'
Get-rCisTagCategory -Name MyCat1 | Set-rCisTagCategory -Cardinality Multiple -Name MyNewCat1 -Description 'Name changed'
Disconnect-rCisServer -Server $cisServer -Confirm:$false

View File

@@ -0,0 +1,13 @@
# Fetch Cis Server hostname and credentials
.\CisConfig.ps1
Connect-rCisServer -Server $cisServer -User $cisUser -Password $cisPswd
Get-rCisTagAssignment -Tag MyNewTag1 | Remove-rCisTagAssignment -Confirm:$false
Get-rCisTag -Name MyNewTag1 | Remove-rCisTag -Confirm:$false
Get-rCisTagCategory -Name MyNewCat1 | Remove-rCisTagCategory -Confirm:$false
Disconnect-rCisServer -Server $cisServer -Confirm:$false

View File

@@ -0,0 +1,20 @@
# Fetch Cis Server hostname and credentials
.\CisConfig.ps1
Connect-rCisServer -Server $cisServer -User $cisUser -Password $cisPswd
$catName = 'Homelab'
# Clean up
Get-rCisTagCategory -Name $catName | Remove-rCisTagCategory -Confirm:$false
# Tag all datastores with their type
New-rCisTagCategory -Name HomeLab -Description 'Homelab datastores' -Cardinality Single -EntityType 'Datastore' |
New-rCisTag -Name 'VMFS','NFS' -Description 'Datastore type'
Get-Cluster -Name Cluster1 | Get-Datastore | %{
New-rCisTagAssignment -Entity $_ -Tag "$($_.Type)"
}
Disconnect-rCisServer -Server $cisServer -Confirm:$false

View File

@@ -0,0 +1,3 @@
$cisServer = 'vcsa.my.domain'
$cisUser = 'administrator@vsphere.local'
$cisPswd = 'VMware1!'

View File

@@ -0,0 +1,21 @@
The MIT License (MIT)
Copyright (c) since 2015 Luc Dekens, Matt Boren
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

15
Modules/rCisTag/README.md Normal file
View File

@@ -0,0 +1,15 @@
# rCisTag
A module with cmdlets to provide CRUD functions to
* Tags
* Tag Categories
* Tag Assignments
The cmdlets use the Cis REST API
## History
* Author : **Luc Dekens**
* Release :
* **0.9.0** First draft

View File

@@ -0,0 +1,26 @@
TOPIC
about_rCISTag
SHORT DESCRIPTION
The rCisTag module provides CRUD functions to work with vSphere Tags
LONG DESCRIPTION
The CisTag module provides CRUD functions to work with vSphere Tags.
The functions in the module are based on the REST API
NOTE
The module requires PowerShell 5.0
TROUBLESHOOTING NOTE
EXAMPLES
Get-rCisTag
KEYWORDS
SEE ALSO
Place related topics here.

File diff suppressed because it is too large Load Diff

Binary file not shown.

Some files were not shown because too many files have changed in this diff Show More