Merge branch 'master' of github.com:thibautnoben/PowerCLI-Example-Scripts
This commit is contained in:
@@ -20,12 +20,12 @@
|
||||
[Parameter(Mandatory=$false)][String]$LibraryName
|
||||
)
|
||||
|
||||
$contentLibaryService = Get-CisService com.vmware.content.library
|
||||
$libaryIDs = $contentLibaryService.list()
|
||||
$contentLibraryService = Get-CisService com.vmware.content.library
|
||||
$LibraryIDs = $contentLibraryService.list()
|
||||
|
||||
$results = @()
|
||||
foreach($libraryID in $libaryIDs) {
|
||||
$library = $contentLibaryService.get($libraryID)
|
||||
foreach($libraryID in $LibraryIDs) {
|
||||
$library = $contentLibraryService.get($libraryID)
|
||||
|
||||
# Use vCenter REST API to retrieve name of Datastore that is backing the Content Library
|
||||
$datastoreService = Get-CisService com.vmware.vcenter.datastore
|
||||
@@ -108,18 +108,18 @@ Function Get-ContentLibraryItems {
|
||||
[Parameter(Mandatory=$false)][String]$LibraryItemName
|
||||
)
|
||||
|
||||
$contentLibaryService = Get-CisService com.vmware.content.library
|
||||
$libaryIDs = $contentLibaryService.list()
|
||||
$contentLibraryService = Get-CisService com.vmware.content.library
|
||||
$LibraryIDs = $contentLibraryService.list()
|
||||
|
||||
$results = @()
|
||||
foreach($libraryID in $libaryIDs) {
|
||||
$library = $contentLibaryService.get($libraryId)
|
||||
foreach($libraryID in $LibraryIDs) {
|
||||
$library = $contentLibraryService.get($libraryId)
|
||||
if($library.name -eq $LibraryName) {
|
||||
$contentLibaryItemService = Get-CisService com.vmware.content.library.item
|
||||
$itemIds = $contentLibaryItemService.list($libraryID)
|
||||
$contentLibraryItemService = Get-CisService com.vmware.content.library.item
|
||||
$itemIds = $contentLibraryItemService.list($libraryID)
|
||||
|
||||
foreach($itemId in $itemIds) {
|
||||
$item = $contentLibaryItemService.get($itemId)
|
||||
$item = $contentLibraryItemService.get($itemId)
|
||||
|
||||
if(!$LibraryItemName) {
|
||||
$itemResult = [pscustomobject] @{
|
||||
@@ -179,28 +179,40 @@ Function Get-ContentLibraryItemFiles {
|
||||
[Parameter(Mandatory=$false)][String]$LibraryItemName
|
||||
)
|
||||
|
||||
$contentLibaryService = Get-CisService com.vmware.content.library
|
||||
$libaryIDs = $contentLibaryService.list()
|
||||
$contentLibraryService = Get-CisService com.vmware.content.library
|
||||
$libraryIDs = $contentLibraryService.list()
|
||||
|
||||
$results = @()
|
||||
foreach($libraryID in $libaryIDs) {
|
||||
$library = $contentLibaryService.get($libraryId)
|
||||
foreach($libraryID in $libraryIDs) {
|
||||
$library = $contentLibraryService.get($libraryId)
|
||||
if($library.name -eq $LibraryName) {
|
||||
$contentLibaryItemService = Get-CisService com.vmware.content.library.item
|
||||
$itemIds = $contentLibaryItemService.list($libraryID)
|
||||
|
||||
$contentLibraryItemService = Get-CisService com.vmware.content.library.item
|
||||
$itemIds = $contentLibraryItemService.list($libraryID)
|
||||
$DatastoreID = $library.storage_backings.datastore_id.Value
|
||||
$Datastore = get-datastore -id "Datastore-$DatastoreID"
|
||||
|
||||
foreach($itemId in $itemIds) {
|
||||
$itemName = ($contentLibaryItemService.get($itemId)).name
|
||||
$contenLibraryItemFileSerice = Get-CisService com.vmware.content.library.item.file
|
||||
$files = $contenLibraryItemFileSerice.list($itemId)
|
||||
$itemName = ($contentLibraryItemService.get($itemId)).name
|
||||
$contentLibraryItemFileSerice = Get-CisService com.vmware.content.library.item.file
|
||||
$files = $contentLibraryItemFileSerice.list($itemId)
|
||||
$contentLibraryItemStorageService = Get-CisService com.vmware.content.library.item.storage
|
||||
|
||||
foreach($file in $files) {
|
||||
if($contentLibraryItemStorageService.get($itemId, $($file.name)).storage_backing.type -eq "DATASTORE"){
|
||||
$filepath = $contentLibraryItemStorageService.get($itemId, $($file.name)).storage_uris.AbsolutePath.split("/")[5..7] -join "/"
|
||||
$fullfilepath = "[$($datastore.name)] $filepath"
|
||||
}
|
||||
else{
|
||||
$fullfilepath = "UNKNOWN"
|
||||
}
|
||||
|
||||
if(!$LibraryItemName) {
|
||||
$fileResult = [pscustomobject] @{
|
||||
Name = $file.name;
|
||||
Version = $file.version;
|
||||
Size = $file.size;
|
||||
Stored = $file.cached;
|
||||
Path = $fullfilepath;
|
||||
}
|
||||
$results+=$fileResult
|
||||
} else {
|
||||
@@ -210,6 +222,7 @@ Function Get-ContentLibraryItemFiles {
|
||||
Version = $file.version;
|
||||
Size = $file.size;
|
||||
Stored = $file.cached;
|
||||
Path = $fullfilepath;
|
||||
}
|
||||
$results+=$fileResult
|
||||
}
|
||||
@@ -245,12 +258,12 @@ Function Set-ContentLibrary {
|
||||
[Parameter(Mandatory=$false)][Switch]$JSONPersistenceDisabled
|
||||
)
|
||||
|
||||
$contentLibaryService = Get-CisService com.vmware.content.library
|
||||
$libaryIDs = $contentLibaryService.list()
|
||||
$contentLibraryService = Get-CisService com.vmware.content.library
|
||||
$LibraryIDs = $contentLibraryService.list()
|
||||
|
||||
$found = $false
|
||||
foreach($libraryID in $libaryIDs) {
|
||||
$library = $contentLibaryService.get($libraryId)
|
||||
foreach($libraryID in $LibraryIDs) {
|
||||
$library = $contentLibraryService.get($libraryId)
|
||||
if($library.name -eq $LibraryName) {
|
||||
$found = $true
|
||||
break
|
||||
@@ -361,12 +374,12 @@ Function Remove-SubscribedContentLibrary {
|
||||
[Parameter(Mandatory=$true)][String]$LibraryName
|
||||
)
|
||||
|
||||
$contentLibaryService = Get-CisService com.vmware.content.library
|
||||
$libaryIDs = $contentLibaryService.list()
|
||||
$contentLibraryService = Get-CisService com.vmware.content.library
|
||||
$LibraryIDs = $contentLibraryService.list()
|
||||
|
||||
$found = $false
|
||||
foreach($libraryID in $libaryIDs) {
|
||||
$library = $contentLibaryService.get($libraryId)
|
||||
foreach($libraryID in $LibraryIDs) {
|
||||
$library = $contentLibraryService.get($libraryId)
|
||||
if($library.name -eq $LibraryName) {
|
||||
$found = $true
|
||||
break
|
||||
@@ -460,12 +473,12 @@ Function Remove-LocalContentLibrary {
|
||||
[Parameter(Mandatory=$true)][String]$LibraryName
|
||||
)
|
||||
|
||||
$contentLibaryService = Get-CisService com.vmware.content.library
|
||||
$libaryIDs = $contentLibaryService.list()
|
||||
$contentLibraryService = Get-CisService com.vmware.content.library
|
||||
$LibraryIDs = $contentLibraryService.list()
|
||||
|
||||
$found = $false
|
||||
foreach($libraryID in $libaryIDs) {
|
||||
$library = $contentLibaryService.get($libraryId)
|
||||
foreach($libraryID in $LibraryIDs) {
|
||||
$library = $contentLibraryService.get($libraryId)
|
||||
if($library.name -eq $LibraryName) {
|
||||
$found = $true
|
||||
break
|
||||
@@ -493,49 +506,49 @@ Function Copy-ContentLibrary {
|
||||
===========================================================================
|
||||
.DESCRIPTION
|
||||
This function copies all library items from one Content Library to another
|
||||
.PARAMETER SourceLibaryName
|
||||
.PARAMETER SourceLibraryName
|
||||
The name of the source Content Library to copy from
|
||||
.PARAMETER DestinationLibaryName
|
||||
.PARAMETER DestinationLibraryName
|
||||
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
|
||||
Copy-ContentLibrary -SourceLibraryName Foo -DestinationLibraryName Bar
|
||||
.EXAMPLE
|
||||
Copy-ContentLibrary -SourceLibaryName Foo -DestinationLibaryName Bar -DeleteSourceFile $true
|
||||
Copy-ContentLibrary -SourceLibraryName Foo -DestinationLibraryName Bar -DeleteSourceFile $true
|
||||
#>
|
||||
param(
|
||||
[Parameter(Mandatory=$true)][String]$SourceLibaryName,
|
||||
[Parameter(Mandatory=$true)][String]$DestinationLibaryName,
|
||||
[Parameter(Mandatory=$true)][String]$SourceLibraryName,
|
||||
[Parameter(Mandatory=$true)][String]$DestinationLibraryName,
|
||||
[Parameter(Mandatory=$false)][Boolean]$DeleteSourceFile=$false
|
||||
)
|
||||
|
||||
$sourceLibraryId = (Get-ContentLibrary -LibraryName $SourceLibaryName).Id
|
||||
$sourceLibraryId = (Get-ContentLibrary -LibraryName $SourceLibraryName).Id
|
||||
if($sourceLibraryId -eq $null) {
|
||||
Write-Host -ForegroundColor red "Unable to find Source Content Library named $SourceLibaryName"
|
||||
Write-Host -ForegroundColor red "Unable to find Source Content Library named $SourceLibraryName"
|
||||
exit
|
||||
}
|
||||
$destinationLibraryId = (Get-ContentLibrary -LibraryName $DestinationLibaryName).Id
|
||||
$destinationLibraryId = (Get-ContentLibrary -LibraryName $DestinationLibraryName).Id
|
||||
if($destinationLibraryId -eq $null) {
|
||||
Write-Host -ForegroundColor Red "Unable to find Destination Content Library named $DestinationLibaryName"
|
||||
Write-Host -ForegroundColor Red "Unable to find Destination Content Library named $DestinationLibraryName"
|
||||
break
|
||||
}
|
||||
|
||||
$sourceItemFiles = Get-ContentLibraryItems -LibraryName $SourceLibaryName
|
||||
$sourceItemFiles = Get-ContentLibraryItems -LibraryName $SourceLibraryName
|
||||
if($sourceItemFiles -eq $null) {
|
||||
Write-Host -ForegroundColor red "Unable to retrieve Content Library Items from $SourceLibaryName"
|
||||
Write-Host -ForegroundColor red "Unable to retrieve Content Library Items from $SourceLibraryName"
|
||||
break
|
||||
}
|
||||
|
||||
$contentLibaryItemService = Get-CisService com.vmware.content.library.item
|
||||
$contentLibraryItemService = 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
|
||||
$result = Get-ContentLibraryItems -LibraryName $DestinationLibraryName -LibraryItemName $sourceItemFile.Name
|
||||
|
||||
if($result -eq $null) {
|
||||
# Create CopySpec
|
||||
$copySpec = $contentLibaryItemService.Help.copy.destination_create_spec.Create()
|
||||
$copySpec = $contentLibraryItemService.Help.copy.destination_create_spec.Create()
|
||||
$copySpec.library_id = $destinationLibraryId
|
||||
$copySpec.name = $sourceItemFile.Name
|
||||
$copySpec.description = $sourceItemFile.Description
|
||||
@@ -545,7 +558,7 @@ Function Copy-ContentLibrary {
|
||||
# Perform Copy
|
||||
try {
|
||||
Write-Host -ForegroundColor Cyan "Copying" $sourceItemFile.Name "..."
|
||||
$copyResult = $contentLibaryItemService.copy($UniqueChangeId, $sourceItemFile.Id, $copySpec)
|
||||
$copyResult = $contentLibraryItemService.copy($UniqueChangeId, $sourceItemFile.Id, $copySpec)
|
||||
} catch {
|
||||
Write-Host -ForegroundColor Red "Failed to copy" $sourceItemFile.Name
|
||||
$Error[0]
|
||||
@@ -556,7 +569,7 @@ Function Copy-ContentLibrary {
|
||||
if($DeleteSourceFile) {
|
||||
try {
|
||||
Write-Host -ForegroundColor Magenta "Deleteing" $sourceItemFile.Name "..."
|
||||
$deleteResult = $contentLibaryItemService.delete($sourceItemFile.Id)
|
||||
$deleteResult = $contentLibraryItemService.delete($sourceItemFile.Id)
|
||||
} catch {
|
||||
Write-Host -ForegroundColor Red "Failed to delete" $sourceItemFile.Name
|
||||
$Error[0]
|
||||
@@ -570,7 +583,7 @@ Function Copy-ContentLibrary {
|
||||
if($DeleteSourceFile) {
|
||||
try {
|
||||
Write-Host -ForegroundColor Magenta "Deleteing" $sourceItemFile.Name "..."
|
||||
$deleteResult = $contentLibaryItemService.delete($sourceItemFile.Id)
|
||||
$deleteResult = $contentLibraryItemService.delete($sourceItemFile.Id)
|
||||
} catch {
|
||||
Write-Host -ForegroundColor Red "Failed to delete" $sourceItemFile.Name
|
||||
break
|
||||
@@ -597,7 +610,7 @@ Function New-VMTX {
|
||||
The name of the VM Template in Content Library
|
||||
.PARAMETER Description
|
||||
Description of the VM template
|
||||
.PARAMETER LibaryName
|
||||
.PARAMETER LibraryName
|
||||
The name of the Content Library to clone to
|
||||
.PARAMETER FolderName
|
||||
The name of vSphere Folder (Defaults to Workloads for VMC)
|
||||
@@ -696,4 +709,4 @@ Function New-VMFromVMTX {
|
||||
|
||||
Write-Host "`nDeploying new VM $NewVMName from VMTX Template $VMTXName ..."
|
||||
$results = $vmtxService.deploy($vmtxId,$vmtxDeploySpec)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,7 +21,8 @@
|
||||
[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"}
|
||||
$body = "refresh_token=$RefreshToken"
|
||||
$results = Invoke-WebRequest -Uri "https://console.cloud.vmware.com/csp/gateway/am/api/auth/api-tokens/authorize" -Method POST -ContentType "application/x-www-form-urlencoded" -UseBasicParsing -Body $body
|
||||
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
|
||||
@@ -51,4 +52,43 @@ Function Get-CSPServices {
|
||||
$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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Function Get-CSPRefreshTokenExpiry {
|
||||
<#
|
||||
.NOTES
|
||||
===========================================================================
|
||||
Created by: William Lam
|
||||
Date: 01/10/2019
|
||||
Organization: VMware
|
||||
Blog: https://www.virtuallyghetto.com
|
||||
Twitter: @lamw
|
||||
===========================================================================
|
||||
|
||||
.DESCRIPTION
|
||||
Retrieve the expiry for a given CSP Refresh Token
|
||||
.PARAMETER RefreshToken
|
||||
Retrieve the expiry for a given CSP Refresh Token
|
||||
.EXAMPLE
|
||||
Get-CSPRefreshTokenExpiry -RefreshToken $RefreshToken
|
||||
#>
|
||||
Param (
|
||||
[Parameter(Mandatory=$true)][String]$RefreshToken
|
||||
)
|
||||
|
||||
$body = @{"tokenValue"="$RefreshToken"}
|
||||
$json = $body | ConvertTo-Json
|
||||
$results = Invoke-WebRequest -Uri "https://console.cloud.vmware.com/csp/gateway/am/api/auth/api-tokens/details" -Method POST -ContentType "application/json" -UseBasicParsing -Body $json
|
||||
$tokenDetails = (($results.Content) | ConvertFrom-Json)
|
||||
|
||||
$createDate = (Get-Date -Date "01/01/1970").AddMilliseconds($tokenDetails.createdAt).ToLocalTime()
|
||||
$usedDate = (Get-Date -Date "01/01/1970").AddMilliseconds($tokenDetails.lastUsedAt).ToLocalTime()
|
||||
$expiryDate = (Get-Date -Date "01/01/1970").AddMilliseconds($tokenDetails.expiresAt).ToLocalTime()
|
||||
|
||||
$tmp = [pscustomobject] @{
|
||||
LastUsedDate = $usedDate;
|
||||
CreatedDate = $createDate;
|
||||
ExpiryDate = $expiryDate;
|
||||
}
|
||||
$tmp | Format-List
|
||||
}
|
||||
|
||||
123
Modules/VMware.Community.CISTag/VMware.Community.CISTag.psd1
Normal file
123
Modules/VMware.Community.CISTag/VMware.Community.CISTag.psd1
Normal file
@@ -0,0 +1,123 @@
|
||||
#
|
||||
# Module manifest for module 'VMware.Community.CISTag'
|
||||
#
|
||||
# Generated by: Kyle Ruddy
|
||||
#
|
||||
# Generated on: 12/14/18
|
||||
#
|
||||
|
||||
@{
|
||||
|
||||
# Script module or binary module file associated with this manifest.
|
||||
RootModule = 'VMware.Community.CISTag.psm1'
|
||||
|
||||
# Version number of this module.
|
||||
ModuleVersion = '1.0.0'
|
||||
|
||||
# Supported PSEditions
|
||||
# CompatiblePSEditions = @()
|
||||
|
||||
# ID used to uniquely identify this module
|
||||
GUID = 'a0803efd-6017-4049-bfc9-5983a5a0c348'
|
||||
|
||||
# Author of this module
|
||||
Author = 'Kyle Ruddy'
|
||||
|
||||
# Company or vendor of this module
|
||||
CompanyName = 'VMware'
|
||||
|
||||
# Copyright statement for this module
|
||||
Copyright = '(c) VMware. All rights reserved.'
|
||||
|
||||
# Description of the functionality provided by this module
|
||||
Description = 'Community sourced PowerShell Module for managing vSphere Tags via the CIS Endpoint'
|
||||
|
||||
# Minimum version of the PowerShell engine required by this module
|
||||
PowerShellVersion = '4.0'
|
||||
|
||||
# Name of the PowerShell host required by this module
|
||||
# PowerShellHostName = ''
|
||||
|
||||
# Minimum version of the PowerShell host required by this module
|
||||
# PowerShellHostVersion = ''
|
||||
|
||||
# Minimum version of Microsoft .NET Framework required by this module. This prerequisite is valid for the PowerShell Desktop edition only.
|
||||
# DotNetFrameworkVersion = ''
|
||||
|
||||
# Minimum version of the common language runtime (CLR) required by this module. This prerequisite is valid for the PowerShell Desktop edition only.
|
||||
# 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 = @()
|
||||
|
||||
# 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 = @()
|
||||
|
||||
# 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-CISTag', 'Get-CISTagCategory', 'Get-CISTagAssignment', 'New-CISTag', 'New-CISTagCategory', 'New-CISTagAssignment', 'Remove-CISTag', 'Remove-CISTagCategory', 'Remove-CISTagAssignment'
|
||||
|
||||
# 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 = ''
|
||||
|
||||
}
|
||||
|
||||
705
Modules/VMware.Community.CISTag/VMware.Community.CISTag.psm1
Normal file
705
Modules/VMware.Community.CISTag/VMware.Community.CISTag.psm1
Normal file
@@ -0,0 +1,705 @@
|
||||
function Get-CISTag {
|
||||
<#
|
||||
.SYNOPSIS
|
||||
Gathers tag information from the CIS REST API endpoint
|
||||
.DESCRIPTION
|
||||
Will provide a list of tags
|
||||
.NOTES
|
||||
Author: Kyle Ruddy, @kmruddy
|
||||
.PARAMETER Name
|
||||
Tag name which should be retreived
|
||||
.PARAMETER Category
|
||||
Tag category name which should be retreived
|
||||
.PARAMETER Id
|
||||
Tag ID which should be retreived
|
||||
.EXAMPLE
|
||||
Get-CISTag
|
||||
Retreives all tag information
|
||||
.EXAMPLE
|
||||
Get-CISTag -Name tagName
|
||||
Retreives the tag information based on the specified name
|
||||
#>
|
||||
[CmdletBinding(SupportsShouldProcess = $True, ConfirmImpact = 'Low')]
|
||||
param(
|
||||
[Parameter(Mandatory=$false,Position=0,ValueFromPipelineByPropertyName=$true)]
|
||||
[String]$Name,
|
||||
[Parameter(Mandatory=$false,Position=1,ValueFromPipelineByPropertyName=$true)]
|
||||
[String]$Category,
|
||||
[Parameter(Mandatory=$false,Position=2,ValueFromPipelineByPropertyName=$true)]
|
||||
[String]$Id
|
||||
)
|
||||
|
||||
If (-Not $global:DefaultCisServers) { Write-error "No CIS Connection found, please use the Connect-CisServer to connect" } Else {
|
||||
$tagSvc = Get-CisService -Name com.vmware.cis.tagging.tag
|
||||
if ($PSBoundParameters.ContainsKey("Id")) {
|
||||
$tagOutput = $tagSvc.get($Id)
|
||||
} else {
|
||||
if ($global:DefaultVIServer -and $global:DefaultVIServer.Name -eq $global:DefaultCisServers.Name) {
|
||||
[Boolean]$vCenterConn = $true
|
||||
$vCTagList = Get-Tag
|
||||
} else {
|
||||
$tagArray = @()
|
||||
$tagIdList = $tagSvc.list() | Select-Object -ExpandProperty Value
|
||||
[integer]$counter = 1
|
||||
foreach ($t in $tagIdList) {
|
||||
$tagArray += $tagSvc.get($t)
|
||||
$counter++
|
||||
if ($counter -gt 200) {Start-Sleep -Milliseconds 1; $counter = 1}
|
||||
}
|
||||
}
|
||||
if ($PSBoundParameters.ContainsKey("Name")) {
|
||||
if ($vCenterConn){
|
||||
$tagOutput = $vCTagList | where {$_.Name -eq $Name}
|
||||
} else {$tagOutput = $tagArray | Where {$_.Name -eq $Name}}
|
||||
} elseif ($PSBoundParameters.ContainsKey("Category")) {
|
||||
if ($vCenterConn){
|
||||
$tagOutput = $vCTagList | where {$_.Category -eq $Category}
|
||||
} else {
|
||||
$tagCatid = Get-CISTagCategory -Name $Category | Select-Object -ExpandProperty Id
|
||||
$tagIdList = $tagSvc.list_tags_for_category($tagCatid)
|
||||
$tagArray2 = @()
|
||||
foreach ($t in $tagIdList) {
|
||||
$tagArray2 += $tagSvc.get($t)
|
||||
}
|
||||
$tagOutput = $tagArray2
|
||||
}
|
||||
} else {
|
||||
if ($vCenterConn){$tagOutput = $vCTagList}
|
||||
else {$tagOutput = $tagArray}
|
||||
}
|
||||
}
|
||||
$tagOutput | Select-Object Id, Name, Description
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
function New-CISTag {
|
||||
<#
|
||||
.SYNOPSIS
|
||||
Creates a new tag from the CIS REST API endpoint
|
||||
.DESCRIPTION
|
||||
Will create a new tag
|
||||
.NOTES
|
||||
Author: Kyle Ruddy, @kmruddy
|
||||
.PARAMETER Name
|
||||
Tag name which should be created
|
||||
.PARAMETER Category
|
||||
Category name where the new tag should be associated
|
||||
.PARAMETER Description
|
||||
Description for the new tag
|
||||
.PARAMETER CategoryID
|
||||
Category ID where the new tag should be associated
|
||||
.EXAMPLE
|
||||
New-CISTag -Name tagName -Category categoryName -Description "Tag Descrition"
|
||||
Creates a new tag based on the specified name
|
||||
#>
|
||||
[CmdletBinding(SupportsShouldProcess = $True, ConfirmImpact = 'Medium')]
|
||||
param(
|
||||
[Parameter(Mandatory=$true,Position=0)]
|
||||
[String]$Name,
|
||||
[Parameter(Mandatory=$false,Position=1)]
|
||||
[String]$Category,
|
||||
[Parameter(Mandatory=$false,Position=2)]
|
||||
[String]$Description,
|
||||
[Parameter(Mandatory=$false,Position=3)]
|
||||
[String]$CategoryID
|
||||
)
|
||||
|
||||
If (-Not $global:DefaultCisServers) { Write-error "No CIS Connection found, please use the Connect-CisServer to connect" } Else {
|
||||
$tagSvc = Get-CisService -Name com.vmware.cis.tagging.tag
|
||||
$tagCreateHelper = $tagSvc.Help.create.create_spec.Create()
|
||||
$tagCreateHelper.name = $Name
|
||||
if ($PSBoundParameters.ContainsKey("Category")) {
|
||||
$tagCreateHelper.category_id = Get-CISTagCategory -Name $Category | Select-Object -ExpandProperty Id
|
||||
} elseif ($PSBoundParameters.ContainsKey("CategoryId")) {
|
||||
$tagCreateHelper.category_id = $CategoryID
|
||||
} else {Write-Warning "No Category input found. Add a Category name or ID."; break}
|
||||
if ($PSBoundParameters.ContainsKey("Description")) {
|
||||
$tagCreateHelper.description = $Description
|
||||
} else {
|
||||
$tagCreateHelper.description = ""
|
||||
}
|
||||
$tagNewId = $tagSvc.create($tagCreateHelper)
|
||||
Get-CISTag -Id $tagNewId
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
function Remove-CISTag {
|
||||
<#
|
||||
.SYNOPSIS
|
||||
Removes a tag from the CIS REST API endpoint
|
||||
.DESCRIPTION
|
||||
Will delete a new tag
|
||||
.NOTES
|
||||
Author: Kyle Ruddy, @kmruddy
|
||||
.PARAMETER Name
|
||||
Tag name which should be removed
|
||||
.PARAMETER ID
|
||||
Tag ID which should be removed
|
||||
.EXAMPLE
|
||||
Remove-CISTag -Name tagName
|
||||
Removes a new tag based on the specified name
|
||||
#>
|
||||
[CmdletBinding(SupportsShouldProcess = $True, ConfirmImpact = 'High')]
|
||||
param(
|
||||
[Parameter(Mandatory=$false,Position=0,ValueFromPipelineByPropertyName=$true)]
|
||||
[String]$Name,
|
||||
[Parameter(Mandatory=$false,Position=1,ValueFromPipelineByPropertyName=$true)]
|
||||
[String]$ID
|
||||
)
|
||||
|
||||
If (-Not $global:DefaultCisServers) { Write-error "No CIS Connection found, please use the Connect-CisServer to connect" } Else {
|
||||
$tagSvc = Get-CisService -Name com.vmware.cis.tagging.tag
|
||||
if ($ID) {
|
||||
$tagSvc.delete($ID)
|
||||
} else {
|
||||
$tagId = Get-CISTag -Name $Name | select -ExpandProperty Id
|
||||
if ($tagId) {$tagSvc.delete($tagId)}
|
||||
else {Write-Warning "No valid tag found."}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function Get-CISTagCategory {
|
||||
<#
|
||||
.SYNOPSIS
|
||||
Gathers tag category information from the CIS REST API endpoint
|
||||
.DESCRIPTION
|
||||
Will provide a list of tag categories
|
||||
.NOTES
|
||||
Author: Kyle Ruddy, @kmruddy
|
||||
.PARAMETER Name
|
||||
Tag category name which should be retreived
|
||||
.PARAMETER Id
|
||||
Tag category ID which should be retreived
|
||||
.EXAMPLE
|
||||
Get-CISTagCategory
|
||||
Retreives all tag category information
|
||||
.EXAMPLE
|
||||
Get-CISTagCategory -Name tagCategoryName
|
||||
Retreives the tag category information based on the specified name
|
||||
#>
|
||||
[CmdletBinding(SupportsShouldProcess = $True, ConfirmImpact = 'Low')]
|
||||
param(
|
||||
[Parameter(Mandatory=$false,Position=0,ValueFromPipelineByPropertyName=$true)]
|
||||
[String]$Name,
|
||||
[Parameter(Mandatory=$false,Position=2,ValueFromPipelineByPropertyName=$true)]
|
||||
[String]$Id
|
||||
)
|
||||
|
||||
If (-Not $global:DefaultCisServers) { Write-error "No CIS Connection found, please use the Connect-CisServer to connect" } Else {
|
||||
$tagCatSvc = Get-CisService -Name com.vmware.cis.tagging.category
|
||||
if ($PSBoundParameters.ContainsKey("Id")) {
|
||||
$tagCatOutput = $tagCatSvc.get($Id)
|
||||
} else {
|
||||
$tagCatArray = @()
|
||||
$tagCatIdList = $tagCatSvc.list() | Select-Object -ExpandProperty Value
|
||||
foreach ($tc in $tagCatIdList) {
|
||||
$tagCatArray += $tagCatSvc.get($tc)
|
||||
}
|
||||
if ($PSBoundParameters.ContainsKey("Name")) {
|
||||
$tagCatOutput = $tagCatArray | Where {$_.Name -eq $Name}
|
||||
} else {
|
||||
$tagCatOutput = $tagCatArray
|
||||
}
|
||||
}
|
||||
$tagCatOutput | Select-Object Id, Name, Description, Cardinality
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
function New-CISTagCategory {
|
||||
<#
|
||||
.SYNOPSIS
|
||||
Creates a new tag category from the CIS REST API endpoint
|
||||
.DESCRIPTION
|
||||
Will create a new tag category
|
||||
.NOTES
|
||||
Author: Kyle Ruddy, @kmruddy
|
||||
.PARAMETER Name
|
||||
Tag category name which should be created
|
||||
.PARAMETER Description
|
||||
Tag category ID which should be retreived
|
||||
.PARAMETER Cardinality
|
||||
Tag category ID which should be retreived
|
||||
.PARAMETER AssociableTypes
|
||||
Tag category ID which should be retreived
|
||||
.EXAMPLE
|
||||
New-CISTagCategory -Name NewTagCategoryName -Description "New Tag Category Description" -Cardinality "Single" -AssociableTypes
|
||||
Creates a new tag category with the specified information
|
||||
#>
|
||||
[CmdletBinding(SupportsShouldProcess = $True, ConfirmImpact = 'Medium')]
|
||||
param(
|
||||
[Parameter(Mandatory=$true,Position=0)]
|
||||
[String]$Name,
|
||||
[Parameter(Mandatory=$false,Position=1)]
|
||||
[String]$Description,
|
||||
[Parameter(Mandatory=$false,Position=2)]
|
||||
[ValidateSet("SINGLE","MULTIPLE")]
|
||||
[String]$Cardinality = "SINGLE",
|
||||
[Parameter(Mandatory=$false,Position=3)]
|
||||
[ValidateSet("All", "Cluster", "Datacenter", "Datastore", "DatastoreCluster", "DistributedPortGroup", "DistributedSwitch", "Folder", "ResourcePool", "VApp", "VirtualPortGroup", "VirtualMachine", "VMHost")]
|
||||
[String]$AssociableTypes = "All"
|
||||
)
|
||||
|
||||
If (-Not $global:DefaultCisServers) { Write-error "No CIS Connection found, please use the Connect-CisServer to connect" } Else {
|
||||
$tagCatSvc = Get-CisService -Name com.vmware.cis.tagging.category
|
||||
$tagCatCreateHelper = $tagCatSvc.Help.create.create_spec.Create()
|
||||
$tagCatCreateHelper.name = $Name
|
||||
if ($PSBoundParameters.ContainsKey("Description")) {
|
||||
$tagCatCreateHelper.description = $Description
|
||||
} else {$tagCatCreateHelper.description = ""}
|
||||
$tagCatCreateHelper.cardinality = $Cardinality
|
||||
$tagCatCreateAssocTypeHelper = $tagCatSvc.help.create.create_spec.associable_types.create()
|
||||
$tagCatCreateAssocTypeHelper.Add($AssociableTypes)
|
||||
$tagCatCreateHelper.associable_types = $tagCatCreateAssocTypeHelper
|
||||
$tagCatNewId = $tagCatSvc.create($tagCatCreateHelper)
|
||||
Get-CISTagCategory -Id $tagCatNewId
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
function Remove-CISTagCategory {
|
||||
<#
|
||||
.SYNOPSIS
|
||||
Removes tag category information from the CIS REST API endpoint
|
||||
.DESCRIPTION
|
||||
Will remove a tag category
|
||||
.NOTES
|
||||
Author: Kyle Ruddy, @kmruddy
|
||||
.PARAMETER Name
|
||||
Tag category name which should be removed
|
||||
.PARAMETER Id
|
||||
Tag category ID which should be removed
|
||||
.EXAMPLE
|
||||
Remove-CISTagCategory -Name tagCategoryName
|
||||
Removes the tag category information based on the specified name
|
||||
|
||||
#>
|
||||
[CmdletBinding(SupportsShouldProcess = $True, ConfirmImpact = 'High')]
|
||||
param(
|
||||
[Parameter(Mandatory=$false,Position=0,ValueFromPipelineByPropertyName=$true)]
|
||||
[String]$Name,
|
||||
[Parameter(Mandatory=$false,Position=2,ValueFromPipelineByPropertyName=$true)]
|
||||
[String]$Id
|
||||
)
|
||||
|
||||
If (-Not $global:DefaultCisServers) { Write-error "No CIS Connection found, please use the Connect-CisServer to connect" } Else {
|
||||
$tagCatSvc = Get-CisService -Name com.vmware.cis.tagging.category
|
||||
if ($PSBoundParameters.ContainsKey("Id")) {
|
||||
$tagCatSvc.delete($Id)
|
||||
} elseif ($PSBoundParameters.ContainsKey("Name")) {
|
||||
$tagCatId = Get-CISTagCategory -Name $Name | Select-Object -ExpandProperty Id
|
||||
$tagCatSvc.delete($tagCatId)
|
||||
} else {Write-Warning "No tag category found."}
|
||||
}
|
||||
}
|
||||
|
||||
function Get-CISTagAssignment {
|
||||
<#
|
||||
.SYNOPSIS
|
||||
Displays a list of the tag assignments from the CIS REST API endpoint
|
||||
.DESCRIPTION
|
||||
Will provide a list of the tag assignments
|
||||
.NOTES
|
||||
Author: Kyle Ruddy, @kmruddy
|
||||
.PARAMETER Category
|
||||
Tag category name which should be referenced
|
||||
.PARAMETER Entity
|
||||
Object name which should be retreived
|
||||
.PARAMETER ObjectId
|
||||
Object ID which should be retreived
|
||||
.EXAMPLE
|
||||
Get-CISTagAssignment
|
||||
Retreives all tag assignment information
|
||||
.EXAMPLE
|
||||
Get-CISTagAssignment -Entity VMName
|
||||
Retreives all tag assignments for the VM name
|
||||
.EXAMPLE
|
||||
Get-CISTagAssignment -ObjectId 'vm-11'
|
||||
Retreives all tag assignments for the VM object
|
||||
#>
|
||||
[CmdletBinding(SupportsShouldProcess = $True, ConfirmImpact = 'Low')]
|
||||
param(
|
||||
[Parameter(Mandatory=$false,Position=0)]
|
||||
[String]$Category,
|
||||
[Parameter(Mandatory=$false,Position=1)]
|
||||
[String]$Entity,
|
||||
[Parameter(Mandatory=$false,Position=2,ValueFromPipelineByPropertyName=$true)]
|
||||
[String]$ObjectId
|
||||
)
|
||||
|
||||
If (-Not $global:DefaultCisServers) { Write-error "No CIS Connection found, please use the Connect-CisServer to connect" } Else {
|
||||
$tagOutput = @()
|
||||
[Boolean]$vCenterConn = $false
|
||||
$tagAssocSvc = Get-CisService -Name com.vmware.cis.tagging.tag_association
|
||||
if ($PSBoundParameters.ContainsKey("ObjectId")) {
|
||||
if ($ObjectId.split('-')[0] -eq 'vm') {
|
||||
$objType = 'VirtualMachine'
|
||||
} else {Write-Warning 'Only VirtualMachine types currently supported.'; break}
|
||||
$objObject = $tagAssocSvc.help.list_attached_tags.object_id.create()
|
||||
$objObject.id = $ObjectId
|
||||
$objObject.type = $objType
|
||||
$tagIdOutput = $tagAssocSvc.list_attached_tags($objObject)
|
||||
} elseif ($PSBoundParameters.ContainsKey("Entity")) {
|
||||
if ($global:DefaultVIServer -and $global:DefaultVIServer.Name -eq $global:DefaultCisServers.Name) {
|
||||
[Boolean]$vCenterConn = $true
|
||||
$viObject = (Get-Inventory -Name $Entity).ExtensionData.MoRef
|
||||
$objObject = $tagAssocSvc.help.list_attached_tags.object_id.create()
|
||||
$objObject.id = $viObject.Value
|
||||
$objObject.type = $viObject.type
|
||||
} else {
|
||||
$vmSvc = Get-CisService -Name com.vmware.vcenter.vm
|
||||
$filterVmNameObj = $vmsvc.help.list.filter.create()
|
||||
$filterVmNameObj.names.add($Entity) | Out-Null
|
||||
$objId = $vmSvc.list($filterVmNameObj) | Select-Object -ExpandProperty vm
|
||||
if ($objId) {$objType = 'VirtualMachine'}
|
||||
else {Write-Warning "No entities found."; break}
|
||||
$objObject = $tagAssocSvc.help.list_attached_tags.object_id.create()
|
||||
$objObject.id = $objId
|
||||
$objObject.type = $objType
|
||||
}
|
||||
$tagIdOutput = $tagAssocSvc.list_attached_tags($objObject)
|
||||
} else {
|
||||
$tagSvc = Get-CisService -Name com.vmware.cis.tagging.tag
|
||||
$tagIdOutput = @()
|
||||
$tagCategories = Get-CISTagCategory | Sort-Object -Property Name
|
||||
if ($Category) {
|
||||
$tagCatId = $tagCategories | where {$_.Name -eq $Category} | Select-Object -ExpandProperty Id
|
||||
$tagIdOutput += $tagSvc.list_tags_for_category($tagCatId)
|
||||
} else {
|
||||
foreach ($tagCat in $tagCategories) {
|
||||
$tagIdOutput += $tagSvc.list_tags_for_category($tagCat.id)
|
||||
}
|
||||
}
|
||||
}
|
||||
$tagReference = Get-CISTag
|
||||
|
||||
if ($Entity -or $ObjectId) {
|
||||
foreach ($tagId in $tagIdOutput) {
|
||||
$tagAttObj = @()
|
||||
if ($Entity) {
|
||||
$tagAttObj += $tagAssocSvc.list_attached_objects($tagId) | where {$_.type -eq $viObject.type -and $_.id -eq $viObject.Value}
|
||||
} else {
|
||||
$tagAttObj += $tagAssocSvc.list_attached_objects($tagId) | where {$_.id -eq $ObjectId}
|
||||
}
|
||||
foreach ($obj in $tagAttObj) {
|
||||
if ($obj.type -eq "VirtualMachine") {
|
||||
if (-Not $vmSvc) {$vmSvc = Get-CisService -Name com.vmware.vcenter.vm}
|
||||
$filterVmObj = $vmsvc.help.list.filter.create()
|
||||
$filterVmObj.vms.add($obj.Id) | Out-Null
|
||||
$objName = $vmSvc.list($filterVmObj) | Select-Object -ExpandProperty Name
|
||||
}
|
||||
else {$objName = 'Object Not Found'}
|
||||
$tempObject = "" | Select-Object Tag, Entity
|
||||
$tempObject.Tag = $tagReference | where {$_.id -eq $tagId} | Select-Object -ExpandProperty Name
|
||||
$tempObject.Entity = $objName
|
||||
$tagOutput += $tempObject
|
||||
}
|
||||
}
|
||||
} else {
|
||||
foreach ($tagId in $tagIdOutput) {
|
||||
$tagAttObj = @()
|
||||
$tagAttObj += $tagAssocSvc.list_attached_objects($tagId)
|
||||
if ($global:DefaultVIServer -and $global:DefaultVIServer.Name -eq $global:DefaultCisServers.Name) {
|
||||
[Boolean]$vCenterConn = $true
|
||||
} elseif ($tagAttObj.Type -contains 'VirtualMachine') {
|
||||
if (-Not $vmSvc) {$vmSvc = Get-CisService -Name com.vmware.vcenter.vm}
|
||||
}
|
||||
foreach ($obj in $tagAttObj) {
|
||||
if ($vCenterConn) {
|
||||
$newViObj = New-Object -TypeName VMware.Vim.ManagedObjectReference
|
||||
$newViObj.Type = $obj.type
|
||||
$newViObj.Value = $obj.id
|
||||
$objName = Get-View -Id $newViObj -Property Name | Select-Object -ExpandProperty Name
|
||||
} elseif ($obj.type -eq "VirtualMachine") {
|
||||
$filterVmObj = $vmsvc.help.list.filter.create()
|
||||
$filterVmObj.vms.add($obj.Id) | Out-Null
|
||||
$objName = $vmSvc.list($filterVmObj) | Select-Object -ExpandProperty Name
|
||||
} else {$objName = 'Object Not Found'}
|
||||
$tempObject = "" | Select-Object Tag, Entity
|
||||
$tempObject.Tag = $tagReference | where {$_.id -eq $tagId} | Select-Object -ExpandProperty Name
|
||||
$tempObject.Entity = $objName
|
||||
$tagOutput += $tempObject
|
||||
}
|
||||
}
|
||||
}
|
||||
return $tagOutput
|
||||
}
|
||||
}
|
||||
|
||||
function New-CISTagAssignment {
|
||||
<#
|
||||
.SYNOPSIS
|
||||
Creates new tag assignments from the CIS REST API endpoint
|
||||
.DESCRIPTION
|
||||
Will create new tag assignments
|
||||
.NOTES
|
||||
Author: Kyle Ruddy, @kmruddy
|
||||
.PARAMETER Tag
|
||||
Tag name which should be referenced
|
||||
.PARAMETER Entity
|
||||
Object name which should be retreived
|
||||
.PARAMETER TagId
|
||||
Tag ID/s which should be referenced
|
||||
.PARAMETER ObjectId
|
||||
Object ID which/s should be retreived
|
||||
.EXAMPLE
|
||||
New-CISTagAssignment -Tag TagName -Entity VMName
|
||||
Creates a tag assignment between the Tag name and the VM name
|
||||
.EXAMPLE
|
||||
New-CISTagAssignment -TagId $tagId -ObjectId 'vm-11'
|
||||
Creates a tag assignment between the Tag ID and the Object ID
|
||||
#>
|
||||
[CmdletBinding(SupportsShouldProcess = $True, ConfirmImpact = 'Medium')]
|
||||
param(
|
||||
[Parameter(Mandatory=$false,Position=0)]
|
||||
$Tag,
|
||||
[Parameter(Mandatory=$false,Position=1)]
|
||||
$Entity,
|
||||
[Parameter(Mandatory=$false,Position=2)]
|
||||
$TagId,
|
||||
[Parameter(Mandatory=$false,Position=3)]
|
||||
$ObjectId
|
||||
)
|
||||
|
||||
If (-Not $global:DefaultCisServers) { Write-error "No CIS Connection found, please use the Connect-CisServer to connect" } Else {
|
||||
$tagAssocSvc = Get-CisService -Name com.vmware.cis.tagging.tag_association
|
||||
if ($PSBoundParameters.ContainsKey("Tag") -and $PSBoundParameters.ContainsKey("Entity")) {
|
||||
if ($Tag -is [array] -and $Entity -isnot [array]) {
|
||||
$tagIdList = $tagAssocSvc.help.attach_multiple_tags_to_object.tag_ids.create()
|
||||
foreach ($t in $Tag) {
|
||||
$tempId = Get-CISTag -Name $t | Select-Object -ExpandProperty Id
|
||||
$tagIdList.add($tempId) | Out-Null
|
||||
}
|
||||
if ($global:DefaultVIServer -and $global:DefaultVIServer.Name -eq $global:DefaultCisServers.Name) {
|
||||
$viObject = (Get-Inventory -Name $Entity).ExtensionData.MoRef
|
||||
$objObject = $tagAssocSvc.help.list_attached_tags.object_id.create()
|
||||
$objObject.id = $viObject.Value
|
||||
$objObject.type = $viObject.type
|
||||
} else {
|
||||
$vmSvc = Get-CisService -Name com.vmware.vcenter.vm
|
||||
$filterVmNameObj = $vmsvc.help.list.filter.create()
|
||||
$filterVmNameObj.names.add($Entity) | Out-Null
|
||||
$objId = $vmSvc.list($filterVmNameObj) | Select-Object -ExpandProperty vm
|
||||
if ($objId) {$objType = 'VirtualMachine'}
|
||||
else {Write-Warning "No entities found."; break}
|
||||
$objObject = $tagAssocSvc.help.list_attached_tags.object_id.create()
|
||||
$objObject.id = $objId
|
||||
$objObject.type = $objType
|
||||
}
|
||||
$tagAssocSvc.attach_multiple_tags_to_object($objObject,$tagIdList) | Out-Null
|
||||
} elseif ($Tag -isnot [array] -and $Entity -is [array]) {
|
||||
$tagId = Get-CISTag -Name $Tag | Select-Object -ExpandProperty Id
|
||||
$objList = $tagAssocSvc.help.attach_tag_to_multiple_objects.object_ids.create()
|
||||
foreach ($e in $Entity) {
|
||||
if ($global:DefaultVIServer -and $global:DefaultVIServer.Name -eq $global:DefaultCisServers.Name) {
|
||||
$viObject = (Get-Inventory -Name $e).ExtensionData.MoRef
|
||||
$objObject = $tagAssocSvc.help.list_attached_tags.object_id.create()
|
||||
$objObject.id = $viObject.Value
|
||||
$objObject.type = $viObject.type
|
||||
} else {
|
||||
$vmSvc = Get-CisService -Name com.vmware.vcenter.vm
|
||||
$filterVmNameObj = $vmsvc.help.list.filter.create()
|
||||
$filterVmNameObj.names.add($Entity) | Out-Null
|
||||
$objId = $vmSvc.list($filterVmNameObj) | Select-Object -ExpandProperty vm
|
||||
if ($objId) {$objType = 'VirtualMachine'}
|
||||
else {Write-Warning "No entities found."; break}
|
||||
$objObject = $tagAssocSvc.help.list_attached_tags.object_id.create()
|
||||
$objObject.id = $objId
|
||||
$objObject.type = $objType
|
||||
}
|
||||
$objList.add($objObject) | Out-Null
|
||||
}
|
||||
$tagAssocSvc.attach_tag_to_multiple_objects($TagId,$objList) | Out-Null
|
||||
} elseif ($Tag -isnot [array] -and $Entity -isnot [array]) {
|
||||
$tagId = Get-CISTag -Name $Tag | Select-Object -ExpandProperty Id
|
||||
if ($global:DefaultVIServer -and $global:DefaultVIServer.Name -eq $global:DefaultCisServers.Name) {
|
||||
$viObject = (Get-Inventory -Name $Entity).ExtensionData.MoRef
|
||||
$objObject = $tagAssocSvc.help.list_attached_tags.object_id.create()
|
||||
$objObject.id = $viObject.Value
|
||||
$objObject.type = $viObject.type
|
||||
} else {
|
||||
$vmSvc = Get-CisService -Name com.vmware.vcenter.vm
|
||||
$filterVmNameObj = $vmsvc.help.list.filter.create()
|
||||
$filterVmNameObj.names.add($Entity) | Out-Null
|
||||
$objId = $vmSvc.list($filterVmNameObj) | Select-Object -ExpandProperty vm
|
||||
if ($objId) {$objType = 'VirtualMachine'}
|
||||
else {Write-Warning "No entities found."; break}
|
||||
$objObject = $tagAssocSvc.help.list_attached_tags.object_id.create()
|
||||
$objObject.id = $objId
|
||||
$objObject.type = $objType
|
||||
}
|
||||
$tagAssocSvc.attach($TagId,$objObject) | Out-Null
|
||||
}
|
||||
} elseif ($PSBoundParameters.ContainsKey("TagId") -and $PSBoundParameters.ContainsKey("ObjectId")) {
|
||||
if ($ObjectId.split('-')[0] -eq 'vm') {
|
||||
$objType = 'VirtualMachine'
|
||||
} else {Write-Warning 'Only VirtualMachine types currently supported.'; break}
|
||||
if ($TagId -is [array] -and $ObjectId -isnot [array]) {
|
||||
$objObject = $tagAssocSvc.help.attach_multiple_tags_to_object.object_id.create()
|
||||
$objObject.id = $ObjectId
|
||||
$objObject.type = $objType
|
||||
$tagIdList = $tagAssocSvc.help.attach_multiple_tags_to_object.tag_ids.create()
|
||||
foreach ($tId in $TagId) {
|
||||
$tagIdList.add($tId) | Out-Null
|
||||
}
|
||||
$tagAssocSvc.attach_multiple_tags_to_object($objObject,$tagIdList) | Out-Null
|
||||
} elseif ($TagId -isnot [array] -and $ObjectId -is [array]) {
|
||||
$objList = $tagAssocSvc.help.attach_tag_to_multiple_objects.object_ids.create()
|
||||
foreach ($obj in $ObjectId) {
|
||||
$objObject = $tagAssocSvc.help.attach_tag_to_multiple_objects.object_ids.element.create()
|
||||
$objObject.id = $obj
|
||||
$objObject.type = $objType
|
||||
$objList.add($objObject) | Out-Null
|
||||
}
|
||||
$tagAssocSvc.attach_tag_to_multiple_objects($TagId,$objList) | Out-Null
|
||||
} elseif ($TagId -isnot [array] -and $ObjectId -isnot [array]) {
|
||||
$objObject = $tagAssocSvc.help.attach.object_id.create()
|
||||
$objObject.id = $ObjectId
|
||||
$objObject.type = $objType
|
||||
$tagAssocSvc.attach($TagId,$objObject) | Out-Null
|
||||
}
|
||||
|
||||
} else {Write-Output "Multiple tags with multiple objects are not a supported call."}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
function Remove-CISTagAssignment {
|
||||
<#
|
||||
.SYNOPSIS
|
||||
Removes a tag assignment from the CIS REST API endpoint
|
||||
.DESCRIPTION
|
||||
Will remove provided tag assignments
|
||||
.NOTES
|
||||
Author: Kyle Ruddy, @kmruddy
|
||||
.PARAMETER Tag
|
||||
Tag name which should be removed
|
||||
.PARAMETER Entity
|
||||
Object name which should be removed
|
||||
.PARAMETER TagId
|
||||
Tag ID/s which should be removed
|
||||
.PARAMETER ObjectId
|
||||
Object ID which/s should be removed
|
||||
.EXAMPLE
|
||||
Remove-CISTagAssignment -TagId $tagId -ObjectId 'vm-11'
|
||||
Removes the tag assignment between the Tag ID and the Object ID
|
||||
.EXAMPLE
|
||||
Remove-CISTagAssignment -Tag TagName -Entity VMName
|
||||
Removes the tag assignment between the Tag name and the Entity name
|
||||
#>
|
||||
[CmdletBinding(SupportsShouldProcess = $True, ConfirmImpact = 'High')]
|
||||
param(
|
||||
[Parameter(Mandatory=$false,Position=0,ValueFromPipelineByPropertyName=$true)]
|
||||
$Tag,
|
||||
[Parameter(Mandatory=$false,Position=1,ValueFromPipelineByPropertyName=$true)]
|
||||
$Entity,
|
||||
[Parameter(Mandatory=$false,Position=2)]
|
||||
$TagId,
|
||||
[Parameter(Mandatory=$false,Position=3)]
|
||||
$ObjectId
|
||||
)
|
||||
|
||||
If (-Not $global:DefaultCisServers) { Write-error "No CIS Connection found, please use the Connect-CisServer to connect" } Else {
|
||||
$tagAssocSvc = Get-CisService -Name com.vmware.cis.tagging.tag_association
|
||||
if ($PSBoundParameters.ContainsKey("Tag") -and $PSBoundParameters.ContainsKey("Entity")) {
|
||||
if ($Tag -is [array] -and $Entity -isnot [array]) {
|
||||
$tagIdList = $tagAssocSvc.help.detach_multiple_tags_from_object.tag_ids.create()
|
||||
foreach ($t in $Tag) {
|
||||
$tempId = Get-CISTag -Name $t | Select-Object -ExpandProperty Id
|
||||
$tagIdList.add($tempId) | Out-Null
|
||||
}
|
||||
if ($global:DefaultVIServer -and $global:DefaultVIServer.Name -eq $global:DefaultCisServers.Name) {
|
||||
$viObject = (Get-Inventory -Name $Entity).ExtensionData.MoRef
|
||||
$objObject = $tagAssocSvc.help.detach_multiple_tags_from_object.object_id.create()
|
||||
$objObject.id = $viObject.Value
|
||||
$objObject.type = $viObject.type
|
||||
} else {
|
||||
$vmSvc = Get-CisService -Name com.vmware.vcenter.vm
|
||||
$filterVmNameObj = $vmsvc.help.list.filter.create()
|
||||
$filterVmNameObj.names.add($Entity) | Out-Null
|
||||
$objId = $vmSvc.list($filterVmNameObj) | Select-Object -ExpandProperty vm
|
||||
if ($objId) {$objType = 'VirtualMachine'}
|
||||
else {Write-Warning "No entities found."; break}
|
||||
$objObject = $tagAssocSvc.help.detach_multiple_tags_from_object.object_id.create()
|
||||
$objObject.id = $objId
|
||||
$objObject.type = $objType
|
||||
}
|
||||
$tagAssocSvc.detach_multiple_tags_from_object($objObject,$tagIdList) | Out-Null
|
||||
} elseif ($Tag -isnot [array] -and $Entity -is [array]) {
|
||||
$tagId = Get-CISTag -Name $Tag | Select-Object -ExpandProperty Id
|
||||
$objList = $tagAssocSvc.help.detach_tag_from_multiple_objects.object_ids.create()
|
||||
foreach ($e in $Entity) {
|
||||
if ($global:DefaultVIServer -and $global:DefaultVIServer.Name -eq $global:DefaultCisServers.Name) {
|
||||
$viObject = (Get-Inventory -Name $e).ExtensionData.MoRef
|
||||
$objObject = $tagAssocSvc.help.detach_tag_from_multiple_objects.object_ids.element.create()
|
||||
$objObject.id = $viObject.Value
|
||||
$objObject.type = $viObject.type
|
||||
} else {
|
||||
$vmSvc = Get-CisService -Name com.vmware.vcenter.vm
|
||||
$filterVmNameObj = $vmsvc.help.list.filter.create()
|
||||
$filterVmNameObj.names.add($Entity) | Out-Null
|
||||
$objId = $vmSvc.list($filterVmNameObj) | Select-Object -ExpandProperty vm
|
||||
if ($objId) {$objType = 'VirtualMachine'}
|
||||
else {Write-Warning "No entities found."; break}
|
||||
$objObject = $tagAssocSvc.help.detach_tag_from_multiple_objects.object_ids.element.create()
|
||||
$objObject.id = $objId
|
||||
$objObject.type = $objType
|
||||
}
|
||||
$objList.add($objObject) | Out-Null
|
||||
}
|
||||
$tagAssocSvc.detach_tag_from_multiple_objects($TagId,$objList) | Out-Null
|
||||
} elseif ($Tag -isnot [array] -and $Entity -isnot [array]) {
|
||||
$tagId = Get-CISTag -Name $Tag | Select-Object -ExpandProperty Id
|
||||
if ($global:DefaultVIServer -and $global:DefaultVIServer.Name -eq $global:DefaultCisServers.Name) {
|
||||
$viObject = (Get-Inventory -Name $Entity).ExtensionData.MoRef
|
||||
$objObject = $tagAssocSvc.help.detach.object_id.create()
|
||||
$objObject.id = $viObject.Value
|
||||
$objObject.type = $viObject.type
|
||||
} else {
|
||||
$vmSvc = Get-CisService -Name com.vmware.vcenter.vm
|
||||
$filterVmNameObj = $vmsvc.help.list.filter.create()
|
||||
$filterVmNameObj.names.add($Entity) | Out-Null
|
||||
$objId = $vmSvc.list($filterVmNameObj) | Select-Object -ExpandProperty vm
|
||||
if ($objId) {$objType = 'VirtualMachine'}
|
||||
else {Write-Warning "No entities found."; break}
|
||||
$objObject = $tagAssocSvc.help.detach.object_id.create()
|
||||
$objObject.id = $objId
|
||||
$objObject.type = $objType
|
||||
}
|
||||
$tagAssocSvc.detach($TagId,$objObject) | Out-Null
|
||||
}
|
||||
} elseif ($PSBoundParameters.ContainsKey("TagId") -and $PSBoundParameters.ContainsKey("ObjectId")) {
|
||||
if ($ObjectId.split('-')[0] -eq 'vm') {
|
||||
$objType = 'VirtualMachine'
|
||||
} else {Write-Warning 'Only VirtualMachine types currently supported.'; break}
|
||||
if ($TagId -is [array] -and $ObjectId -isnot [array]) {
|
||||
$objObject = $tagAssocSvc.help.detach_multiple_tags_from_object.object_id.create()
|
||||
$objObject.id = $ObjectId
|
||||
$objObject.type = $objType
|
||||
$tagIdList = $tagAssocSvc.help.detach_multiple_tags_from_object.tag_ids.create()
|
||||
foreach ($tId in $TagId) {
|
||||
$tagIdList.add($tId) | Out-Null
|
||||
}
|
||||
$tagAssocSvc.detach_multiple_tags_from_object($objObject,$tagIdList) | Out-Null
|
||||
} elseif ($TagId -isnot [array] -and $ObjectId -is [array]) {
|
||||
$objList = $tagAssocSvc.help.detach_tag_from_multiple_objects.object_ids.create()
|
||||
foreach ($obj in $ObjectId) {
|
||||
$objObject = $tagAssocSvc.help.detach_tag_from_multiple_objects.object_ids.element.create()
|
||||
$objObject.id = $obj
|
||||
$objObject.type = $objType
|
||||
$objList.add($objObject) | Out-Null
|
||||
}
|
||||
$tagAssocSvc.detach_tag_from_multiple_objects($TagId,$objList) | Out-Null
|
||||
} elseif ($TagId -isnot [array] -and $ObjectId -isnot [array]) {
|
||||
$objObject = $tagAssocSvc.help.detach.object_id.create()
|
||||
$objObject.id = $ObjectId
|
||||
$objObject.type = $objType
|
||||
$tagAssocSvc.detach($TagId,$objObject) | Out-Null
|
||||
}
|
||||
} else {Write-Output "Multiple tags with multiple objects are not a supported call."}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -3666,13 +3666,19 @@ function New-HVPool {
|
||||
# flashSettings
|
||||
#desktopSpec.desktopSettings.flashSettings.quality
|
||||
[Parameter(Mandatory = $false,ParameterSetName = "LINKED_CLONE")]
|
||||
[Parameter(Mandatory = $false,ParameterSetName = 'INSTANT_CLONE')]
|
||||
[Parameter(Mandatory = $false,ParameterSetName = 'FULL_CLONE')]
|
||||
[Parameter(Mandatory = $false,ParameterSetName = 'MANUAL')]
|
||||
[ValidateSet('NO_CONTROL', 'LOW', 'MEDIUM', 'HIGH')]
|
||||
[string]$quality = 'NO_CONTROL',
|
||||
[string]$Quality = 'NO_CONTROL',
|
||||
|
||||
#desktopSpec.desktopSettings.flashSettings.throttling
|
||||
[Parameter(Mandatory = $false,ParameterSetName = "LINKED_CLONE")]
|
||||
[Parameter(Mandatory = $false,ParameterSetName = 'INSTANT_CLONE')]
|
||||
[Parameter(Mandatory = $false,ParameterSetName = 'FULL_CLONE')]
|
||||
[Parameter(Mandatory = $false,ParameterSetName = 'MANUAL')]
|
||||
[ValidateSet('DISABLED', 'CONSERVATIVE', 'MODERATE', 'AGGRESSIVE')]
|
||||
[string]$throttling = 'DISABLED',
|
||||
[string]$Throttling = 'DISABLED',
|
||||
|
||||
#mirageConfigurationOverrides
|
||||
#desktopSpec.desktopSettings.mirageConfigurationOverrides.overrideGlobalSetting
|
||||
@@ -7172,7 +7178,6 @@ function Get-HVMachine {
|
||||
$machineList = Find-HVMachine -Param $PSBoundParameters
|
||||
if (!$machineList) {
|
||||
Write-Host "Get-HVMachine: No Virtual Machine(s) Found with given search parameters"
|
||||
break
|
||||
}
|
||||
$queryResults = @()
|
||||
$desktop_helper = New-Object VMware.Hv.MachineService
|
||||
@@ -9319,6 +9324,16 @@ function Set-HVApplicationIcon {
|
||||
}
|
||||
|
||||
process {
|
||||
if (!(Test-Path $IconPath)) {
|
||||
Write-Error "File:[$IconPath] does not exist."
|
||||
break
|
||||
}
|
||||
|
||||
if ([IO.Path]::GetExtension($IconPath) -ne '.png') {
|
||||
Write-Error "Unsupported file format:[$IconPath]. Only PNG image files are supported."
|
||||
break
|
||||
}
|
||||
|
||||
try {
|
||||
$appInfo = Get-HVQueryResult -EntityType ApplicationInfo -Filter (Get-HVQueryFilter data.name -Eq $ApplicationName) -HvServer $HvServer
|
||||
} catch {
|
||||
@@ -9332,11 +9347,6 @@ function Set-HVApplicationIcon {
|
||||
break
|
||||
}
|
||||
|
||||
if (!(Test-Path $IconPath)) {
|
||||
Write-Error "File:[$IconPath] does not exists"
|
||||
break
|
||||
}
|
||||
|
||||
$spec = New-Object VMware.Hv.ApplicationIconSpec
|
||||
$base = New-Object VMware.Hv.ApplicationIconBase
|
||||
|
||||
@@ -10170,7 +10180,7 @@ $deleteSpec.DeleteFromDisk = $DeleteFromDisk
|
||||
$deleteSpec.ArchivePersistentDisk = $false
|
||||
|
||||
#Delete the machines
|
||||
write-host "Attempting to Delete:"
|
||||
if($DeleteFromDisk){write-host "Attempting to Delete:"}else{write-host "Attempting to remove from inventory:"}
|
||||
Write-Output ($deleteMachine.base.Name -join "`n")
|
||||
$bye = $machineService.Machine_DeleteMachines($services,$deleteMachine.id,$deleteSpec)
|
||||
|
||||
@@ -11477,4 +11487,102 @@ function Get-HVlicense {
|
||||
[System.gc]::collect()
|
||||
}
|
||||
|
||||
Export-ModuleMember Add-HVDesktop,Add-HVRDSServer,Connect-HVEvent,Disconnect-HVEvent,Get-HVPoolSpec,Get-HVInternalName, Get-HVEvent,Get-HVFarm,Get-HVFarmSummary,Get-HVPool,Get-HVPoolSummary,Get-HVMachine,Get-HVMachineSummary,Get-HVQueryResult,Get-HVQueryFilter,New-HVFarm,New-HVPool,Remove-HVFarm,Remove-HVPool,Set-HVFarm,Set-HVPool,Start-HVFarm,Start-HVPool,New-HVEntitlement,Get-HVEntitlement,Remove-HVEntitlement, Set-HVMachine, New-HVGlobalEntitlement, Remove-HVGlobalEntitlement, Get-HVGlobalEntitlement, Set-HVApplicationIcon, Remove-HVApplicationIcon, Get-HVGlobalSettings, Set-HVGlobalSettings, Set-HVGlobalEntitlement, Get-HVResourceStructure, Get-HVLocalSession, Get-HVGlobalSession, Reset-HVMachine, Remove-HVMachine, Get-HVHealth, New-HVPodfederation, Remove-HVPodFederation, Get-HVPodFederation, Register-HVPod, Unregister-HVPod, Set-HVPodFederation,Get-HVSite,New-HVSite,Set-HVSite,Remove-HVSite,New-HVHomeSite,Get-HVHomeSite,Set-HVEventDatabase,Get-HVEventDatabase,Clear-HVEventDatabase,Get-HVlicense,Set-HVlicense
|
||||
function Set-HVInstantCloneMaintenance {
|
||||
<#
|
||||
.Synopsis
|
||||
Enable or disable instant clone maintanence mode
|
||||
|
||||
.DESCRIPTION
|
||||
Toggles a host in instant clone maintanence mode. Specify the VMHost name and enable or disable to toggle.
|
||||
|
||||
.PARAMETER VMHost
|
||||
ESXi Host name to modify the InstantClone.Maintenance attribute
|
||||
|
||||
.PARAMETER Enable
|
||||
Enable Instant Clone maintenance mode.
|
||||
|
||||
.PARAMETER Disable
|
||||
Disable Instant Clone maintenance mode
|
||||
|
||||
.EXAMPLE
|
||||
Set-HvInstantCloneMaintenance -VMHost <hostname> -Enable $true
|
||||
Set-HvInstantCloneMaintenance -VMHost <hostname> -Disable $true
|
||||
|
||||
.NOTES
|
||||
Author : Jack McMichael
|
||||
Author email : @jackwmc4 / jackwmc4@gmail.com
|
||||
Version : 1.0
|
||||
|
||||
===Tested Against Environment====
|
||||
Horizon View Server Version : 7.6
|
||||
PowerCLI Version : PowerCLI 11
|
||||
PowerShell Version : 5.1
|
||||
#>
|
||||
|
||||
[CmdletBinding(
|
||||
SupportsShouldProcess = $true,
|
||||
ConfirmImpact = 'High')]
|
||||
|
||||
param(
|
||||
[Parameter(Mandatory=$true, Position=0)]
|
||||
[string]
|
||||
$VMHost,
|
||||
|
||||
[Parameter(Mandatory = $false)]
|
||||
[switch]
|
||||
$Enable,
|
||||
|
||||
[Parameter(Mandatory = $false)]
|
||||
[switch]
|
||||
$Disable,
|
||||
|
||||
[Parameter(Mandatory = $false)]
|
||||
$HvServer = $null
|
||||
)
|
||||
|
||||
begin {
|
||||
$services = Get-ViewAPIService -hvServer $hvServer
|
||||
if ($null -eq $services) {
|
||||
Write-Error "Could not retrieve ViewApi services from connection object"
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
process {
|
||||
if ($Enable) {
|
||||
if ((Get-Annotation -Entity (Get-VMHost -Name $VMHost) -CustomAttribute "InstantClone.Maintenance").Value -eq ""){
|
||||
Set-Annotation -Entity (Get-VMHost -Name $VMHost) -CustomAttribute "InstantClone.Maintenance" -Value "1" | Out-Null
|
||||
Write-Host "Instant Clone Maintenance Mode: Enabling for $VMHost...(This could take some time)"
|
||||
}
|
||||
while ((Get-Annotation -Entity (Get-VMHost -Name $VMHost) -CustomAttribute "InstantClone.Maintenance").Value -ne "2") {
|
||||
Start-Sleep -Seconds 10
|
||||
}
|
||||
} elseif ($Disable) {
|
||||
if (-not (Get-Annotation -Entity (Get-VMHost -Name $VMHost) -CustomAttribute "InstantClone.Maintenance").Value -eq "") {
|
||||
Set-Annotation -Entity (Get-VMHost -Name $VMHost) -CustomAttribute "InstantClone.Maintenance" -Value "" | Out-Null
|
||||
Write-Host "Instant Clone Maintenance Mode: Disabling for $VMHost"
|
||||
}
|
||||
Set-VMhost $VMHost -State Connected | Out-Null
|
||||
}
|
||||
[System.gc]::collect()
|
||||
}
|
||||
}
|
||||
# Object related
|
||||
Export-ModuleMember -Function Get-HVMachine, Get-HVMachineSummary, Get-HVQueryResult, Get-HVQueryFilter, Get-HVInternalName
|
||||
# RDS Farm related
|
||||
Export-ModuleMember -Function Get-HVFarmSummary, Start-HVFarm, Start-HVPool, New-HVFarm, Remove-HVFarm, Get-HVFarm, Set-HVFarm, Add-HVRDSServer
|
||||
# Desktop Pool related
|
||||
Export-ModuleMember -Function Get-HVPoolSummary, New-HVPool, Remove-HVPool, Get-HVPool, Set-HVPool, Get-HVPoolSpec, Add-HVDesktop
|
||||
# Entitlement related
|
||||
Export-ModuleMember -Function New-HVEntitlement,Get-HVEntitlement,Remove-HVEntitlement
|
||||
Export-ModuleMember -Function Set-HVMachine, Reset-HVMachine, Remove-HVMachine
|
||||
# Cloud Pod Architecture related
|
||||
Export-ModuleMember -Function New-HVGlobalEntitlement, Remove-HVGlobalEntitlement, Get-HVGlobalEntitlement, Set-HVGlobalEntitlement, New-HVPodFederation, Remove-HVPodFederation, Get-HVPodFederation, Set-HVPodFederation
|
||||
Export-ModuleMember -Function Get-HVSite, New-HVSite, New-HVHomeSite, Remove-HVSite, Get-HVHomeSite, Set-HVSite, Register-HVPod, Unregister-HVPod
|
||||
# Published App related
|
||||
Export-ModuleMember -Function Get-HVGlobalSettings, Set-HVApplicationIcon, Remove-HVApplicationIcon, Set-HVGlobalSettings
|
||||
Export-ModuleMember -Function Get-HVResourceStructure, Get-HVLocalSession, Get-HVGlobalSession
|
||||
# Event Database related
|
||||
Export-ModuleMember -Function Get-HVEventDatabase, Set-HVEventDatabase, Clear-HVEventDatabase, Get-HVEvent, Connect-HVEvent, Disconnect-HVEvent
|
||||
# Misc/other related
|
||||
Export-ModuleMember -Function Get-HVlicense, Set-HVlicense, Get-HVHealth, Set-HVInstantCloneMaintenance
|
||||
|
||||
1057
Modules/VMware.VCGChecker/Export-VCGReport.ps1
Normal file
1057
Modules/VMware.VCGChecker/Export-VCGReport.ps1
Normal file
File diff suppressed because it is too large
Load Diff
310
Modules/VMware.VCGChecker/Get-VCGHWInfo.ps1
Normal file
310
Modules/VMware.VCGChecker/Get-VCGHWInfo.ps1
Normal 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
|
||||
}
|
||||
168
Modules/VMware.VCGChecker/Get-VCGStatus.ps1
Normal file
168
Modules/VMware.VCGChecker/Get-VCGStatus.ps1
Normal 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
|
||||
}
|
||||
41
Modules/VMware.VCGChecker/README.md
Normal file
41
Modules/VMware.VCGChecker/README.md
Normal 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 <path_to_VMware.VCGChecker.psd1>
|
||||
|
||||
2. Connect to the target vSphere hosts using Connect-VIServer and get VMHosts
|
||||
PS> Connect-VIServer -Server <server> -User <username> -Password <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 '<release>'
|
||||
|
||||
5. Save the compatibility reports
|
||||
PS> Export-VCGReport -Data $vcgdata -Dir <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.
|
||||
17
Modules/VMware.VCGChecker/Save-VCGJsonFile.ps1
Normal file
17
Modules/VMware.VCGChecker/Save-VCGJsonFile.ps1
Normal 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
|
||||
}
|
||||
90
Modules/VMware.VCGChecker/VMware.VCGChecker.psd1
Normal file
90
Modules/VMware.VCGChecker/VMware.VCGChecker.psd1
Normal 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 = ''
|
||||
|
||||
}
|
||||
112
Modules/VMware.VCGChecker/logger.ps1
Normal file
112
Modules/VMware.VCGChecker/logger.ps1
Normal 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")
|
||||
@@ -36,7 +36,7 @@ Description = 'PowerShell Module for Managing NSX-T on VMware Cloud on AWS'
|
||||
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'
|
||||
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', 'Get-NSXTDistFirewallSection', 'Get-NSXTDistFirewall', 'New-NSXTDistFirewall', 'Remove-NSXTDistFirewall', 'Get-NSXTRouteTable', 'Get-NSXTOverviewInfo'
|
||||
# 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 = @()
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
Binary file not shown.
File diff suppressed because it is too large
Load Diff
7
Modules/VMware.VsanEncryption/README.md
Normal file
7
Modules/VMware.VsanEncryption/README.md
Normal file
@@ -0,0 +1,7 @@
|
||||
Prerequisites/Steps to use this module:
|
||||
|
||||
1. This module only works for vSphere products that support vSAN Encryption. E.g. vSAN 6.6 and later with a vSAN Enterprise license
|
||||
2. All the functions in this module only work for KMIP Servers.
|
||||
3. Install the latest version of Powershell and PowerCLI(11).
|
||||
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.
|
||||
BIN
Modules/VMware.VsanEncryption/VMware.VsanEncryption.psd1
Normal file
BIN
Modules/VMware.VsanEncryption/VMware.VsanEncryption.psd1
Normal file
Binary file not shown.
341
Modules/VMware.VsanEncryption/VMware.VsanEncryption.psm1
Normal file
341
Modules/VMware.VsanEncryption/VMware.VsanEncryption.psm1
Normal file
@@ -0,0 +1,341 @@
|
||||
# Script Module : VMware.VsanEncryption
|
||||
# Version : 1.0
|
||||
# Author : Jase McCarty, VMware Storage & Availability Business Unit
|
||||
|
||||
# Copyright © 2018 VMware, Inc. All Rights Reserved.
|
||||
|
||||
# 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.
|
||||
|
||||
|
||||
Function Invoke-VsanEncryptionRekey {
|
||||
<#
|
||||
.SYNOPSIS
|
||||
This function will initiate a ReKey of a vSAN Cluster. Shallow ReKeying (KEK Only) or Deep ReKeying (DEK Also) are supported, as well as Reduced Redundancy if necessary.
|
||||
|
||||
.DESCRIPTION
|
||||
This function will initiate a ReKey of a vSAN Cluster. Shallow ReKeying (KEK Only) or Deep ReKeying (DEK Also) are supported, as well as Reduced Redundancy if necessary.
|
||||
|
||||
.PARAMETER Cluster
|
||||
Specifies the Cluster to perform the rekey process on
|
||||
|
||||
.PARAMETER DeepRekey
|
||||
Use to invoke a Deep Rekey ($true) or a Shallow ($false or omit)
|
||||
|
||||
.PARAMETER ReducedRedundancy
|
||||
For clusters that have 4 or more hosts, this will allow for reduced redundancy.
|
||||
For clusters that have 2 or 3 hosts, this does not need to be set (can be).
|
||||
|
||||
.EXAMPLE
|
||||
C:\PS>Invoke-VsanEncryptionRekey -Cluster "ClusterName" -DeepRekey $true/$false -ReducedRedundancy $true/$false
|
||||
|
||||
#>
|
||||
|
||||
# Set our Parameters
|
||||
[CmdletBinding()]Param(
|
||||
[Parameter(Mandatory = $True)][String]$Cluster,
|
||||
[Parameter(Mandatory = $False)][Boolean]$DeepRekey,
|
||||
[Parameter(Mandatory = $False)][Boolean]$ReducedRedundancy
|
||||
)
|
||||
|
||||
# Get the Cluster
|
||||
$VsanCluster = Get-Cluster -Name $Cluster
|
||||
|
||||
# Get the vSAN Cluster Configuration View
|
||||
$VsanVcClusterConfig = Get-VsanView -Id "VsanVcClusterConfigSystem-vsan-cluster-config-system"
|
||||
|
||||
# Get Encryption State
|
||||
$EncryptedVsan = $VsanVcClusterConfig.VsanClusterGetConfig($VsanCluster.ExtensionData.MoRef).DataEncryptionConfig
|
||||
|
||||
# If vSAN is enabled and it is Encrypted
|
||||
If($VsanCluster.vSanEnabled -And $EncryptedVsan.EncryptionEnabled){
|
||||
|
||||
# Get a count of hosts to guarantee reduced redundancy for 2 and 3 node clusters
|
||||
$HostCount = $VsanCluster | Select @{n="count";e={($_ | Get-VMHost).Count}}
|
||||
|
||||
# If reduced redundancy is specified, or there are less than 4 hosts, force reduced redundancy
|
||||
If (($ReducedRedundancy -eq $true) -or ($HostCount.Value -lt 4)) {
|
||||
|
||||
}
|
||||
# Determine Rekey Type for messaging
|
||||
Switch ($DeepRekey) {
|
||||
$true { $ReKeyType = "deep"}
|
||||
default { $ReKeyType = "shallow"}
|
||||
}
|
||||
|
||||
# Determine Reduced Redundancy for messaging
|
||||
Switch ($ReducedRedundancy) {
|
||||
$true { $RRMessage = "with reduced redundancy"}
|
||||
default { $RRMessage = ""}
|
||||
}
|
||||
|
||||
# Echo task being performed
|
||||
Write-Host "Executing $ReKeyType rekey of vSAN Cluster $VsanCluster $RRMessage"
|
||||
|
||||
# Execute the rekeying task
|
||||
$ReKeyTask = $VsanVcClusterConfig.VsanEncryptedClusterRekey_Task($VsanCluster.ExtensionData.MoRef,$DeepRekey,$ReducedRedundancy)
|
||||
}
|
||||
}
|
||||
|
||||
Function Set-VsanEncryptionKms {
|
||||
<#
|
||||
.SYNOPSIS
|
||||
This function will set the KMS to be used with vSAN Encryption
|
||||
|
||||
.DESCRIPTION
|
||||
This function will set the KMS to be used with vSAN Encryption
|
||||
|
||||
.PARAMETER Cluster
|
||||
Specifies the Cluster to set the KMS server for
|
||||
|
||||
.PARAMETER KmsCluster
|
||||
Use to set the KMS Cluster to be used with vSAN Encryption
|
||||
|
||||
.EXAMPLE
|
||||
C:\PS>Set-VsanEncryptionKms -Cluster "ClusterName" -KmsCluster "vCenter KMS Cluster Entry"
|
||||
|
||||
#>
|
||||
|
||||
# Set our Parameters
|
||||
[CmdletBinding()]Param(
|
||||
[Parameter(Mandatory = $True)][String]$Cluster,
|
||||
[Parameter(Mandatory = $False)][String]$KmsCluster
|
||||
)
|
||||
|
||||
# Get the Cluster
|
||||
$VsanCluster = Get-Cluster -Name $Cluster
|
||||
|
||||
# Get the list of KMS Servers that are included
|
||||
$KmsClusterList = Get-KmsCluster
|
||||
|
||||
# Was a KMS Cluster Specified?
|
||||
# Specified: Is it in the list?
|
||||
# Is it not in the list?
|
||||
# Not Specified: Present a list
|
||||
If ($KmsCluster) {
|
||||
If ($KmsClusterList.Name.Contains($KmsCluster)) {
|
||||
Write-Host "$KmsCluster In the list, proceeding" -ForegroundColor Green
|
||||
$KmsClusterProfile = $KmsClusterList | Where-Object {$_.Name -eq $KmsCluster}
|
||||
} else {
|
||||
|
||||
$Count = 0
|
||||
Foreach ($KmsClusterItem in $KmsClusterList) {
|
||||
Write-Host "$Count) $KmsClusterItem "
|
||||
$Count = $Count + 1
|
||||
}
|
||||
$KmsClusterEntry = Read-Host -Prompt "$KmsCluster is not valid, please select one of the existing KMS Clusters to use"
|
||||
Write-Host $KmsClusterList[$KmsClusterEntry]
|
||||
$KmsClusterProfile = $KmsClusterList[$KmsClusterEntry]
|
||||
}
|
||||
} else {
|
||||
|
||||
$Count = 0
|
||||
Foreach ($KmsClusterItem in $KmsClusterList) {
|
||||
Write-Host "$Count) $KmsClusterItem "
|
||||
$Count = $Count + 1
|
||||
}
|
||||
$KmsClusterEntry = Read-Host -Prompt "No KMS provided, please select one of the existing KMS Clusters to use"
|
||||
Write-Host $KmsClusterList[$KmsClusterEntry]
|
||||
$KmsClusterProfile = $KmsClusterList[$KmsClusterEntry]
|
||||
}
|
||||
|
||||
# Get the vSAN Cluster Configuration View
|
||||
$VsanVcClusterConfig = Get-VsanView -Id "VsanVcClusterConfigSystem-vsan-cluster-config-system"
|
||||
|
||||
# Get Encryption State
|
||||
$EncryptedVsan = $VsanVcClusterConfig.VsanClusterGetConfig($VsanCluster.ExtensionData.MoRef).DataEncryptionConfig
|
||||
|
||||
# If vSAN is enabled and it is Encrypted
|
||||
If($VsanCluster.vSanEnabled -And $EncryptedVsan.EncryptionEnabled){
|
||||
|
||||
If ($EncryptedVsan.KmsProviderId.Id -eq $KmsClusterProfile.Name) {
|
||||
# If the Specified KMS Profile is the KMS Profile being used, then don't do anything
|
||||
Write-Host $EncryptedVsan.KmsProviderId.Id "is already the assigned KMS Cluster Profile, exiting"
|
||||
} else {
|
||||
Write-Host "Changing the KMS Profile to $KmsClusterProfile on Cluster $VsanCluster"
|
||||
|
||||
# Setup the KMS Provider Id Specification
|
||||
$KmsProviderIdSpec = New-Object VMware.Vim.KeyProviderId
|
||||
$KmsProviderIdSpec.Id = $KmsClusterProfile.Name
|
||||
|
||||
# Setup the Data Encryption Configuration Specification
|
||||
$DataEncryptionConfigSpec = New-Object VMware.Vsan.Views.VsanDataEncryptionConfig
|
||||
$DataEncryptionConfigSpec.KmsProviderId = $KmsProviderIdSpec
|
||||
$DataEncryptionConfigSpec.EncryptionEnabled = $true
|
||||
|
||||
# Set the Reconfigure Specification to use the Data Encryption Configuration Spec
|
||||
$vsanReconfigSpec = New-Object VMware.Vsan.Views.VimVsanReconfigSpec
|
||||
$vsanReconfigSpec.DataEncryptionConfig = $DataEncryptionConfigSpec
|
||||
|
||||
# Execute the task of changing the KMS Cluster Profile Being Used
|
||||
$ChangeKmsTask = $VsanVcClusterConfig.VsanClusterReconfig($VsanCluster.ExtensionData.MoRef,$vsanReconfigSpec)
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
Function Get-VsanEncryptionKms {
|
||||
<#
|
||||
.SYNOPSIS
|
||||
This function will set the KMS to be used with vSAN Encryption
|
||||
|
||||
.DESCRIPTION
|
||||
This function will set the KMS to be used with vSAN Encryption
|
||||
|
||||
.PARAMETER Cluster
|
||||
Specifies the Cluster to set the KMS server for
|
||||
|
||||
.EXAMPLE
|
||||
C:\PS>Get-VsanEncryptionKms -Cluster "ClusterName"
|
||||
#>
|
||||
|
||||
# Set our Parameters
|
||||
[CmdletBinding()]Param([Parameter(Mandatory = $True)][String]$Cluster)
|
||||
|
||||
# Get the Cluster
|
||||
$VsanCluster = Get-Cluster -Name $Cluster
|
||||
|
||||
# Get the vSAN Cluster Configuration View
|
||||
$VsanVcClusterConfig = Get-VsanView -Id "VsanVcClusterConfigSystem-vsan-cluster-config-system"
|
||||
|
||||
# Get Encryption State
|
||||
$EncryptedVsan = $VsanVcClusterConfig.VsanClusterGetConfig($VsanCluster.ExtensionData.MoRef).DataEncryptionConfig
|
||||
|
||||
# If vSAN is enabled and it is Encrypted
|
||||
If($VsanCluster.vSanEnabled -And $EncryptedVsan.EncryptionEnabled){
|
||||
|
||||
$EncryptedVsan.KmsProviderId.Id
|
||||
}
|
||||
}
|
||||
|
||||
Function Set-VsanEncryptionDiskWiping {
|
||||
<#
|
||||
.SYNOPSIS
|
||||
This function will update the Disk Wiping option in vSAN Encryption
|
||||
|
||||
.DESCRIPTION
|
||||
This function will update the Disk Wiping option in vSAN Encryption
|
||||
|
||||
.PARAMETER Cluster
|
||||
Specifies the Cluster set the Disk Wiping Setting on
|
||||
|
||||
.PARAMETER DiskWiping
|
||||
Use to set the Disk Wiping setting for vSAN Encryption
|
||||
|
||||
.EXAMPLE
|
||||
C:\PS>Set-VsanEncryptionDiskWiping -Cluster "ClusterName" -DiskWiping $true
|
||||
|
||||
.EXAMPLE
|
||||
C:\PS>Set-VsanEncryptionDiskWiping -Cluster "ClusterName" -DiskWiping $false
|
||||
|
||||
#>
|
||||
|
||||
# Set our Parameters
|
||||
[CmdletBinding()]Param(
|
||||
[Parameter(Mandatory = $True)][String]$Cluster,
|
||||
[Parameter(Mandatory = $True)][Boolean]$DiskWiping
|
||||
)
|
||||
|
||||
# Get the Cluster
|
||||
$VsanCluster = Get-Cluster -Name $Cluster
|
||||
|
||||
# Get the vSAN Cluster Configuration View
|
||||
$VsanVcClusterConfig = Get-VsanView -Id "VsanVcClusterConfigSystem-vsan-cluster-config-system"
|
||||
|
||||
# Get Encryption State
|
||||
$EncryptedVsan = $VsanVcClusterConfig.VsanClusterGetConfig($VsanCluster.ExtensionData.MoRef).DataEncryptionConfig
|
||||
|
||||
# If vSAN is enabled and it is Encrypted
|
||||
If($VsanCluster.vSanEnabled -And $EncryptedVsan.EncryptionEnabled){
|
||||
|
||||
# Determine Rekey Type for messaging
|
||||
Switch ($DiskWiping) {
|
||||
$true { $DiskWipingSetting = "enabled" }
|
||||
default { $DiskWipingSetting = "disabled" }
|
||||
}
|
||||
|
||||
# Check to see the current Disk Wiping value
|
||||
If ($DiskWiping -eq $EncryptedVsan.EraseDisksBeforeUse) {
|
||||
Write-Host "Disk Wiping is already $DiskWipingSetting" -ForegroundColor "Green"
|
||||
Write-Host "No action necessary" -ForegroundColor "Green"
|
||||
|
||||
} else {
|
||||
|
||||
Write-Host "Disk Wiping is not set to $DiskWipingSetting" -ForegroundColor "Yellow"
|
||||
Write-Host "Changing Disk Wiping setting on Cluster $VsanCluster" -ForegroundColor "Blue"
|
||||
|
||||
# Setup the Data Encryption Configuration Specification
|
||||
$DataEncryptionConfigSpec = New-Object VMware.Vsan.Views.VsanDataEncryptionConfig
|
||||
$DataEncryptionConfigSpec.EncryptionEnabled = $true
|
||||
$DataEncryptionConfigSpec.EraseDisksBeforeUse = $DiskWiping
|
||||
|
||||
# Set the Reconfigure Specification to use the Data Encryption Configuration Spec
|
||||
$vsanReconfigSpec = New-Object VMware.Vsan.Views.VimVsanReconfigSpec
|
||||
$vsanReconfigSpec.DataEncryptionConfig = $DataEncryptionConfigSpec
|
||||
|
||||
# Execute the task of changing the KMS Cluster Profile Being Used
|
||||
$VsanVcClusterConfig.VsanClusterReconfig($VsanCluster.ExtensionData.MoRef,$vsanReconfigSpec)
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Function Get-VsanEncryptionDiskWiping {
|
||||
<#
|
||||
.SYNOPSIS
|
||||
This function will retrieve the Disk Wiping option setting in vSAN Encryption
|
||||
|
||||
.DESCRIPTION
|
||||
This function will retrieve the Disk Wiping option setting in vSAN Encryption
|
||||
|
||||
.PARAMETER Cluster
|
||||
Specifies the Cluster set the Disk Wiping Setting on
|
||||
|
||||
.EXAMPLE
|
||||
C:\PS>Get-VsanEncryptionDiskWiping -Cluster "ClusterName"
|
||||
|
||||
#>
|
||||
|
||||
# Set our Parameters
|
||||
[CmdletBinding()]Param([Parameter(Mandatory = $True)][String]$Cluster)
|
||||
|
||||
# Get the Cluster
|
||||
$VsanCluster = Get-Cluster -Name $Cluster
|
||||
|
||||
# Get the vSAN Cluster Configuration View
|
||||
$VsanVcClusterConfig = Get-VsanView -Id "VsanVcClusterConfigSystem-vsan-cluster-config-system"
|
||||
|
||||
# Get Encryption State
|
||||
$EncryptedVsan = $VsanVcClusterConfig.VsanClusterGetConfig($VsanCluster.ExtensionData.MoRef).DataEncryptionConfig
|
||||
|
||||
# If vSAN is enabled and it is Encrypted
|
||||
If($VsanCluster.vSanEnabled -And $EncryptedVsan.EncryptionEnabled){
|
||||
|
||||
# Change the setting
|
||||
$EncryptedVsan.EraseDisksBeforeUse
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
# Export Function for vSAN Rekeying
|
||||
Export-ModuleMember -Function Invoke-VsanEncryptionRekey
|
||||
Export-ModuleMember -Function Set-VsanEncryptionKms
|
||||
Export-ModuleMember -Function Get-VsanEncryptionKms
|
||||
Export-ModuleMember -Function Set-VsanEncryptionDiskWiping
|
||||
Export-ModuleMember -Function Get-VsanEncryptionDiskWiping
|
||||
74
Modules/vCenterCEIP/vCenterCEIP.psm1
Executable file
74
Modules/vCenterCEIP/vCenterCEIP.psm1
Executable file
@@ -0,0 +1,74 @@
|
||||
Function Get-VCenterCEIP {
|
||||
<#
|
||||
.NOTES
|
||||
===========================================================================
|
||||
Created by: William Lam
|
||||
Date: 01/23/2019
|
||||
Organization: VMware
|
||||
Blog: http://www.virtuallyghetto.com
|
||||
Twitter: @lamw
|
||||
===========================================================================
|
||||
|
||||
.SYNOPSIS
|
||||
Retrieves the the Customer Experience Improvement Program (CEIP) setting for vCenter Server
|
||||
.DESCRIPTION
|
||||
This cmdlet retrieves the the CEIP setting for vCenter Server
|
||||
.EXAMPLE
|
||||
Get-VCenterCEIP
|
||||
#>
|
||||
If (-Not $global:DefaultVIServer.IsConnected) { Write-error "No valid VC Connection found, please use the Connect-VIServer to connect"; break } Else {
|
||||
$ceipSettings = (Get-AdvancedSetting -Entity $global:DefaultVIServer -Name VirtualCenter.DataCollector.ConsentData).Value.toString() | ConvertFrom-Json
|
||||
$ceipEnabled = $ceipSettings.consentConfigurations[0].consentAccepted
|
||||
|
||||
$tmp = [pscustomobject] @{
|
||||
VCENTER = $global:DefaultVIServer.Name;
|
||||
CEIP = $ceipEnabled;
|
||||
}
|
||||
$tmp
|
||||
}
|
||||
}
|
||||
Function Set-VCenterCEIP {
|
||||
<#
|
||||
.NOTES
|
||||
===========================================================================
|
||||
Created by: William Lam
|
||||
Date: 01/23/2019
|
||||
Organization: VMware
|
||||
Blog: http://www.virtuallyghetto.com
|
||||
Twitter: @lamw
|
||||
===========================================================================
|
||||
|
||||
.SYNOPSIS
|
||||
Enables or Disables the Customer Experience Improvement Program (CEIP) setting for vCenter Server
|
||||
.DESCRIPTION
|
||||
This cmdlet enables or disables the CEIP setting for vCenter Server
|
||||
.EXAMPLE
|
||||
Set-VCenterCEIP -Enabled
|
||||
.EXAMPLE
|
||||
Set-VCenterCEIP -Disabled
|
||||
#>
|
||||
Param (
|
||||
[Switch]$Enabled,
|
||||
[Switch]$Disabled
|
||||
)
|
||||
If (-Not $global:DefaultVIServer.IsConnected) { Write-error "No valid VC Connection found, please use the Connect-VIServer to connect"; break } Else {
|
||||
$ceipSettings = (Get-AdvancedSetting -Entity $global:DefaultVIServer -Name VirtualCenter.DataCollector.ConsentData).Value.toString() | ConvertFrom-Json
|
||||
If($Enabled) {
|
||||
$originalVersion = $ceipSettings.version
|
||||
$ceipSettings.version = [int]$originalVersion + 1
|
||||
$ceipSettings.consentConfigurations[0].consentAccepted = $True
|
||||
$ceipSettings.consentConfigurations[1].consentAccepted = $True
|
||||
$updatedceipSettings = $ceipSettings | ConvertTo-Json
|
||||
Write-Host "Enabling Customer Experience Improvement Program (CEIP) ..."
|
||||
Get-AdvancedSetting -Entity $global:DefaultVIServer -Name VirtualCenter.DataCollector.ConsentData | Set-AdvancedSetting -Value $updatedceipSettings -Confirm:$false
|
||||
} else {
|
||||
$originalVersion = $ceipSettings.version
|
||||
$ceipSettings.version = [int]$originalVersion + 1
|
||||
$ceipSettings.consentConfigurations[0].consentAccepted = $False
|
||||
$ceipSettings.consentConfigurations[1].consentAccepted = $False
|
||||
$updatedceipSettings = $ceipSettings | ConvertTo-Json
|
||||
Write-Host "Disablng Customer Experience Improvement Program (CEIP) ..."
|
||||
Get-AdvancedSetting -Entity $global:DefaultVIServer -Name VirtualCenter.DataCollector.ConsentData | Set-AdvancedSetting -Value $updatedceipSettings -Confirm:$false
|
||||
}
|
||||
}
|
||||
}
|
||||
34
Scripts/Move-DatastoreCluster.ps1
Normal file
34
Scripts/Move-DatastoreCluster.ps1
Normal file
@@ -0,0 +1,34 @@
|
||||
function Move-DatastoreCluster {
|
||||
<#
|
||||
.SYNOPSIS
|
||||
Moves a datastore cluster to a new location
|
||||
.DESCRIPTION
|
||||
Will move a datastore cluster to a new location
|
||||
.NOTES
|
||||
Author: Kyle Ruddy, @kmruddy
|
||||
.PARAMETER DatastoreCluster
|
||||
Specifies the datastore cluster you want to move.
|
||||
.PARAMETER Destination
|
||||
Specifies a destination where you want to place the datastore cluster
|
||||
.EXAMPLE
|
||||
Move-DatastoreCluster -DatastoreCluster $DSCluster -Destination $DSClusterFolder
|
||||
Moves the $DSCluster datastore cluster to the specified $DSClusterFolder folder.
|
||||
#>
|
||||
[CmdletBinding(SupportsShouldProcess = $True)]
|
||||
param(
|
||||
[Parameter(Mandatory=$false,Position=0,ValueFromPipelineByPropertyName=$true)]
|
||||
[VMware.VimAutomation.ViCore.Types.V1.DatastoreManagement.DatastoreCluster]$DatastoreCluster,
|
||||
[Parameter(Mandatory=$false,Position=1,ValueFromPipelineByPropertyName=$true)]
|
||||
[VMware.VimAutomation.ViCore.Types.V1.Inventory.Folder]$Destination
|
||||
)
|
||||
|
||||
if ($Global:DefaultVIServer.IsConnected -eq $false) {
|
||||
Write-Warning -Message "No vCenter Server connection found."
|
||||
break
|
||||
}
|
||||
|
||||
If ($Pscmdlet.ShouldProcess($DatastoreCluster,"Move Datastore Cluster")) {
|
||||
$Destination.ExtensionData.MoveIntoFolder($DatastoreCluster.ExtensionData.MoRef)
|
||||
}
|
||||
|
||||
}
|
||||
147
Scripts/Save-PowerCLI.ps1
Normal file
147
Scripts/Save-PowerCLI.ps1
Normal file
@@ -0,0 +1,147 @@
|
||||
function Save-PowerCLI {
|
||||
<#
|
||||
.SYNOPSIS
|
||||
Advanced function which can be used to easily download specific versions of PowerCLI from an online gallery
|
||||
.DESCRIPTION
|
||||
Downloads a specific version of PowerCLI and all the dependencies at the appropriate version
|
||||
.NOTES
|
||||
Author: 1.0 - Dimitar Milov
|
||||
Author: 2.0 - Kyle Ruddy, @kmruddy
|
||||
.PARAMETER RequiredVersion
|
||||
Dynamic parameter used to specify the PowerCLI version
|
||||
.PARAMETER Path
|
||||
Directory path where the modules should be downloaded
|
||||
.PARAMETER Repository
|
||||
Repository to access the PowerCLI modules
|
||||
.PARAMETER Simple
|
||||
Switch used to specify the nested version folders should be removed (therefore adding PowerShell 3/4 compatibility)
|
||||
.EXAMPLE
|
||||
Save-PowerCLI -RequiredVersion '10.0.0.7895300' -Path .\Downloads\
|
||||
Downloads PowerCLI 10.0.0 to the Downloads folder
|
||||
.EXAMPLE
|
||||
Save-PowerCLI -RequiredVersion '6.5.2.6268016' -Path .\Downloads\ -Simple
|
||||
Downloads PowerCLI 6.5.2 to the Downloads folder and removes the nested version folders
|
||||
#>
|
||||
[CmdletBinding(SupportsShouldProcess = $True)]
|
||||
param(
|
||||
[Parameter(Mandatory = $true, Position = 1)]
|
||||
[ValidateScript( { Test-Path $_} )]
|
||||
$Path,
|
||||
[Parameter(Mandatory = $false, Position = 2)]
|
||||
[string]$Repository = 'PSGallery',
|
||||
[Parameter(Mandatory = $false, Position = 3)]
|
||||
[Switch]$Simple
|
||||
)
|
||||
DynamicParam
|
||||
{
|
||||
# Set the dynamic parameters name
|
||||
$ParameterName = 'RequiredVersion'
|
||||
|
||||
# Create the dictionary
|
||||
$RuntimeParameterDictionary = New-Object System.Management.Automation.RuntimeDefinedParameterDictionary
|
||||
|
||||
# Create the collection of attributes
|
||||
$AttributeCollection = New-Object System.Collections.ObjectModel.Collection[System.Attribute]
|
||||
|
||||
# Create and set the parameters' attributes
|
||||
$ParameterAttribute = New-Object System.Management.Automation.ParameterAttribute
|
||||
$ParameterAttribute.ValueFromPipeline = $true
|
||||
$ParameterAttribute.ValueFromPipelineByPropertyName = $true
|
||||
$ParameterAttribute.Mandatory = $true
|
||||
$ParameterAttribute.Position = 0
|
||||
|
||||
# Add the attributes to the attributes collection
|
||||
$AttributeCollection.Add($ParameterAttribute)
|
||||
|
||||
# Generate and set the ValidateSet
|
||||
$pcliVersions = Find-Module -Name 'VMware.PowerCLI' -AllVersions
|
||||
$arrSet = $pcliVersions | select-Object -ExpandProperty Version
|
||||
$ValidateSetAttribute = New-Object System.Management.Automation.ValidateSetAttribute($arrSet)
|
||||
|
||||
# Add the ValidateSet to the attributes collection
|
||||
$AttributeCollection.Add($ValidateSetAttribute)
|
||||
|
||||
# Create and return the dynamic parameter
|
||||
$RuntimeParameter = New-Object System.Management.Automation.RuntimeDefinedParameter($ParameterName, [string], $AttributeCollection)
|
||||
$RuntimeParameterDictionary.Add($ParameterName, $RuntimeParameter)
|
||||
return $RuntimeParameterDictionary
|
||||
}
|
||||
|
||||
begin {
|
||||
$powercliModuleName = 'VMware.PowerCLI'
|
||||
$desiredPowerCLIModule = Find-Module -Name $powercliModuleName -RequiredVersion $RequiredVersion -Repository $Repository
|
||||
|
||||
$depsOrder = 'VMware.VimAutomation.Sdk', 'VMware.VimAutomation.Common', 'VMware.Vim', 'VMware.VimAutomation.Cis.Core', 'VMware.VimAutomation.Core', 'VMware.VimAutomation.Nsxt', 'VMware.VimAutomation.Vmc', 'VMware.VimAutomation.Vds', 'VMware.VimAutomation.Srm', 'VMware.ImageBuilder', 'VMware.VimAutomation.Storage', 'VMware.VimAutomation.StorageUtility', 'VMware.VimAutomation.License', 'VMware.VumAutomation', 'VMware.VimAutomation.HorizonView', 'VMware.DeployAutomation', 'VMware.VimAutomation.vROps', 'VMware.VimAutomation.PCloud'
|
||||
$orderedDependencies = @()
|
||||
foreach ($depModuleName in $depsOrder) {
|
||||
$orderedDependencies += $desiredPowerCLIModule.Dependencies | Where-Object {$_.Name -eq $depModuleName}
|
||||
}
|
||||
|
||||
foreach ($remainingDep in $desiredPowerCLIModule.Dependencies) {
|
||||
if ($orderedDependencies.Name -notcontains $remainingDep.Name) {
|
||||
$orderedDependencies += $remainingDep
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
process {
|
||||
# Save PowerCLI Module Version
|
||||
$desiredPowerCLIModule | Save-Module -Path $Path
|
||||
|
||||
# Working with the depenent modules
|
||||
foreach ($dependency in $orderedDependencies) {
|
||||
if (Get-ChildItem -Path (Join-Path $path $dependency.Name) | Where-Object {$_.Name -ne $dependency.MinimumVersion}) {
|
||||
# Save dependencies with minimum version
|
||||
Find-Module $dependency.Name -RequiredVersion $dependency.MinimumVersion | Save-Module -Path $Path
|
||||
|
||||
# Remove newer dependencies version
|
||||
Get-ChildItem -Path (Join-Path $path $dependency.Name) | Where-Object {$_.Name -ne $dependency.MinimumVersion} | Remove-Item -Confirm:$false -Force -Recurse
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
end {
|
||||
if ($Simple) {
|
||||
|
||||
function FolderCleanup {
|
||||
param(
|
||||
[Parameter(Mandatory = $true, Position = 0)]
|
||||
[ValidateScript( { Test-Path $_} )]
|
||||
$ParentFolder,
|
||||
[Parameter(Mandatory = $true, Position = 1)]
|
||||
[String]$ModuleName,
|
||||
[Parameter(Mandatory = $true, Position = 2)]
|
||||
$Version
|
||||
)
|
||||
|
||||
|
||||
$topFolder = Get-Item -Path (Join-Path $ParentFolder $ModuleName)
|
||||
$versionFolder = $topFolder | Get-ChildItem -Directory | Where-Object {$_.Name -eq $Version}
|
||||
$versionFolder | Get-ChildItem | Copy-Item -Destination $topFolder
|
||||
|
||||
# Checking for any nested folders within the PowerCLI module version folder
|
||||
if ($versionFolder| Get-ChildItem -Directory) {
|
||||
|
||||
# Obtaining and storing the child items to a variable, then copying the items to the parent folder's nested folder
|
||||
$nestFolder = $versionFolder| Get-ChildItem -Directory
|
||||
foreach ($nestDir in $nestFolder) {
|
||||
$nestDir | Get-ChildItem | Copy-Item -Destination (Join-Path $topFolder $nestDir.Name)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
# Removing any of the former, no longer needed, directory structure
|
||||
$versionFolder| Remove-Item -Recurse -Force
|
||||
}
|
||||
|
||||
FolderCleanup -ParentFolder $Path -ModuleName $desiredPowerCLIModule.Name -Version $desiredPowerCLIModule.Version
|
||||
foreach ($cleanUp in $orderedDependencies) {
|
||||
|
||||
FolderCleanup -ParentFolder $Path -ModuleName $cleanUp.Name -Version $cleanUp.MinimumVersion
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
50
Scripts/Set-NetworkAdapterOpaqueNetwork.ps1
Normal file
50
Scripts/Set-NetworkAdapterOpaqueNetwork.ps1
Normal file
@@ -0,0 +1,50 @@
|
||||
function Set-NetworkAdapterOpaqueNetwork {
|
||||
param(
|
||||
[Parameter(Mandatory = $true, ValueFromPipeline = $true, Position = 1)]
|
||||
[VMware.VimAutomation.Types.NetworkAdapter]
|
||||
$NetworkAdapter,
|
||||
|
||||
[Parameter(Mandatory = $true, Position = 2)]
|
||||
[string]
|
||||
$OpaqueNetworkName,
|
||||
|
||||
[Parameter()]
|
||||
[switch]
|
||||
$Connected,
|
||||
|
||||
[Parameter()]
|
||||
[switch]
|
||||
$StartConnected
|
||||
)
|
||||
process {
|
||||
$opaqueNetwork = Get-View -ViewType OpaqueNetwork | ? {$_.Name -eq $OpaqueNetworkName}
|
||||
if (-not $opaqueNetwork) {
|
||||
throw "'$OpaqueNetworkName' network not found."
|
||||
}
|
||||
|
||||
$opaqueNetworkBacking = New-Object VMware.Vim.VirtualEthernetCardOpaqueNetworkBackingInfo
|
||||
$opaqueNetworkBacking.OpaqueNetworkId = $opaqueNetwork.Summary.OpaqueNetworkId
|
||||
$opaqueNetworkBacking.OpaqueNetworkType = $opaqueNetwork.Summary.OpaqueNetworkType
|
||||
|
||||
$device = $NetworkAdapter.ExtensionData
|
||||
$device.Backing = $opaqueNetworkBacking
|
||||
|
||||
if ($StartConnected) {
|
||||
$device.Connectable.StartConnected = $true
|
||||
}
|
||||
|
||||
if ($Connected) {
|
||||
$device.Connectable.Connected = $true
|
||||
}
|
||||
|
||||
$spec = New-Object VMware.Vim.VirtualDeviceConfigSpec
|
||||
$spec.Operation = [VMware.Vim.VirtualDeviceConfigSpecOperation]::edit
|
||||
$spec.Device = $device
|
||||
$configSpec = New-Object VMware.Vim.VirtualMachineConfigSpec
|
||||
$configSpec.DeviceChange = @($spec)
|
||||
$NetworkAdapter.Parent.ExtensionData.ReconfigVM($configSpec)
|
||||
|
||||
# Output
|
||||
Get-NetworkAdapter -Id $NetworkAdapter.Id
|
||||
}
|
||||
}
|
||||
22
Scripts/backup-esxi-host-configuration.ps1
Normal file
22
Scripts/backup-esxi-host-configuration.ps1
Normal file
@@ -0,0 +1,22 @@
|
||||
<#
|
||||
Script name: backup-esxi-host-configuration.ps1
|
||||
Created on: 09/10/2018
|
||||
Author: Gerasimos Alexiou, @jerrak0s
|
||||
Description: The purpose of the script is to backup esxi host configuration for restore purposes.
|
||||
Dependencies: None known
|
||||
|
||||
===Tested Against Environment====
|
||||
vSphere Version: 6.5 U2
|
||||
PowerCLI Version: PowerCLI 10.1.1
|
||||
PowerShell Version: 5.1
|
||||
OS Version: Windows 10
|
||||
Keyword: Backup Configuration ESXi Host
|
||||
#>
|
||||
|
||||
|
||||
$serverIp = Read-Host 'What is the server ip address:'
|
||||
$path = Read-Host 'Give path where backup configuration will be stored:'
|
||||
$serverPass = Read-Host 'What is the server root password:' -AsSecureString
|
||||
Set-PowerCLIConfiguration -InvalidCertificateAction Ignore -Confirm:$false
|
||||
Connect-VIServer serverip -user "root" -password $serverPass
|
||||
Get-VMHostFirmware -vmhost serverip -BackupConfiguration -DestinationPath $path
|
||||
Reference in New Issue
Block a user