From e8896d388fdf8e2b751d91d60b07da0711d7b55e Mon Sep 17 00:00:00 2001 From: jrob24 Date: Thu, 21 Sep 2017 23:30:31 -0500 Subject: [PATCH 01/29] Add files via upload --- Modules/vCenter.Alarms/New-vCenterAlarms.ps1 | 79 ++ Modules/vCenter.Alarms/vCenter.Alarms.psm1 | 736 +++++++++++++++++++ 2 files changed, 815 insertions(+) create mode 100644 Modules/vCenter.Alarms/New-vCenterAlarms.ps1 create mode 100644 Modules/vCenter.Alarms/vCenter.Alarms.psm1 diff --git a/Modules/vCenter.Alarms/New-vCenterAlarms.ps1 b/Modules/vCenter.Alarms/New-vCenterAlarms.ps1 new file mode 100644 index 0000000..e3ba5c8 --- /dev/null +++ b/Modules/vCenter.Alarms/New-vCenterAlarms.ps1 @@ -0,0 +1,79 @@ +<# + + =========================================================================== + Created by: Jason Robinson + Created on: 05/2017 + Twitter: @jrob24 + Filename: New-vCenterAlarms.ps1 + =========================================================================== + .DESCRIPTION + Examples of creating alarms using vCenter.Alarm module +#> + +Import-Module -Name vCenter.Alarms + +Write-Verbose -Message "Example 1 : Creating new Host CPU Usage alarm (Metric based alarm)" +Write-Verbose -Message "Finding the metric id for 'cpu.usage.average'" +$MetricId = (Get-MetricId -MetricGroup CPU | Where-Object -FilterScript { $_.Name -eq 'cpu.usage.average' }).Key +Write-Verbose -Message "Creating an alarm trigger for cpu.usage.average of 90% for 15mins (Warning) & 95% for 10mins (Alert) on the HostSystem object type" +$Trigger = New-AlarmTrigger -MetricId $MetricId -MetricOperator isAbove -ObjectType HostSystem -Yellow 90 -YellowInterval 15 -Red 95 -RedInterval 10 +Write-Verbose -Message "Creates a new alarm called 'Host CPU Usage' at the root level of vCenter" +New-AlarmDefinition -Name "Host CPU Usage" -Description "Alarm on 95%" -Entity Datacenters -Trigger $Trigger -ActionRepeatMinutes 10 +Write-Verbose -Message "Configures the alarm to send snmp traps" +Get-AlarmDefinition -Name "Host CPU Usage" | vSphere.Alarms\New-AlarmAction -Snmp -GreenToYellow Once -YellowToRed Repeat + +Write-Verbose -Message "Example 2 : Creating new HA Disabled alarm (Event based alarm)" +Write-Verbose -Message "Finding the event type for 'HA disabled for cluster'" +$EventType = (Get-EventId | Where-Object -FilterScript { $_.Description -match 'HA disabled for cluster' }).EventType +Write-Verbose -Message "Creating an alarm trigger for 'DasDisabledEvent' on the ClusterComputeResource object type" +$Trigger = New-AlarmTrigger -EventType $EventType -Status Red -ObjectType ClusterComputeResource +Write-Verbose -Message "Creates a new alarm called 'HA Disabled' at the root level of vCenter" +New-AlarmDefinition -Name "HA Disabled" -Description "Alarm on HA" -Entity Datacenters -Trigger $Trigger -ActionRepeatMinutes 30 +Write-Verbose -Message "Configures the alarm to send an email every 30mins" +$EmailParams = @{ + Email = $true + To = 'helpdesk@company.com' + Subject = 'HA Disabled' +} +Get-AlarmDefinition -Name "HA Disabled" | vCenter.Alarms\New-AlarmAction @EmailParams -YellowToRed Repeat + +Write-Verbose -Message "Example 3 : Creating new Host Connection State alarm (State based alarm)" +Write-Verbose -Message "Creating an alarm trigger for StateType of 'runtime.connectionState' on the HostSystem object type" +$Trigger = New-AlarmTrigger -StateType runtime.connectionState -StateOperator isEqual -YellowStateCondition disconnected -RedStateCondition notResponding -ObjectType HostSystem +Write-Verbose -Message "Creates a new alarm called 'Host Connection State' at the root level of vCenter" +New-AlarmDefinition -Name "Host Connection State" -Description "Connection State" -Entity Datacenters -Trigger $Trigger +Write-Verbose -Message "Configures the alarm to send an email once" +$EmailParams = @{ + Email = $true + To = 'helpdesk@company.com' + Subject = 'Host Connection Lost' +} +Get-AlarmDefinition -Name "Host Connection State" | vCenter.Alarms\New-AlarmAction @EmailParams -YellowToRed Once + +Write-Verbose -Message "Example 4 : Creating new Lost Storage Connectivity (Event based alarm)" +Write-Verbose -Message "Find the event type for 'Lost Storage Connectivity'" +Get-EventId | Where-Object -FilterScript { $_.Description -match 'Lost Storage Connectivity' } +Write-Verbose -Message "Two results returned, we want esx not vprob" + <# + EventType : EventEx + EventTypeId : esx.problem.storage.connectivity.lost + Category : error + Description : Lost Storage Connectivity + FullFormat : Lost connectivity to storage device { 1 }. Path { 2 } is down. Affected datastores: { 3 }. + vCenter : vCenter01 + + EventType : EventEx + EventTypeId : vprob.storage.connectivity.lost + Category : error + Description : Lost Storage Connectivity + FullFormat : Lost connectivity to storage device { 1 }. Path { 2 } is down. Affected datastores: { 3 }. + vCenter : vCenter01 + #> +Write-Verbose -Message "Since the event type is EventEx, we need both the EventType & EventTypeId to create the trigger" +$EventType = Get-EventId | Where-Object -FilterScript { $_.EventTypeId -eq 'esx.problem.storage.connectivity.lost' } +Write-Verbose -Message "Creating an alarm trigger for 'DasDisabledEvent' on the ClusterComputeResource object type" +$Trigger = New-AlarmTrigger -EventType $EventType.EventType -EventTypeId $EventType.EventTypeId -Status Red -ObjectType HostSystem +Write-Verbose -Message "Creates a new alarm called 'Lost Storage Connectivity' at the root level of vCenter" +New-AlarmDefinition -Name "Lost Storage Connectivity" -Description "Lost Storage" -Entity Datacenters -Trigger $Trigger -ActionRepeatMinutes 5 +Write-Verbose -Message "Configures the alarm to send an snmp every 5mins" +Get-AlarmDefinition -Name "Lost Storage Connectivity" | vCenter.Alarms\New-AlarmAction -Snmp -YellowToRed Repeat \ No newline at end of file diff --git a/Modules/vCenter.Alarms/vCenter.Alarms.psm1 b/Modules/vCenter.Alarms/vCenter.Alarms.psm1 new file mode 100644 index 0000000..80d625f --- /dev/null +++ b/Modules/vCenter.Alarms/vCenter.Alarms.psm1 @@ -0,0 +1,736 @@ +<# + =========================================================================== + Created by: Jason Robinson + Created on: 05/2017 + Twitter: @jrob24 + =========================================================================== + .DESCRIPTION + PowerShell Module to help with creation of vCenter Alarms + .NOTES + See New-vCenterAlarms.ps1 for examples of alarm creation + + * Tested against PowerShell 5.0 + * Tested against PowerCLI 6.5.1 build 5377412 + * Tested against vCenter 6.0 + * Tested against ESXi 5.5/6.0 +#> + +function New-AlarmDefinition { +<# + .SYNOPSIS + This cmdlet creates a new alarm defintion on the specified entity in vCenter. + .DESCRIPTION + This cmdlet creates a new alarm defintion on the specified entity in vCenter. + An alarm trigger is required in order to create a new alarm definition. + They can be created by using the New-AlarmTrigger cmdlet. + + After the alarm definition is created, if alarm actions are required use + the cmdlet New-AlarmAction to create actions for the alarm. + .PARAMETER Name + Specifies the name of the alarm you want to create. + .PARAMETER Description + Specifies the description for the alarm. + .PARAMETER Entity + Specifies where to create the alarm. To create the alarm at the root + level of vCenter use the entity 'Datacenters', otherwise specify any + object name. + .PARAMETER Trigger + Specifies the alarm event, state, or metric trigger(s). The alarm + trigger(s) are created with the New-AlarmTrigger cmdlet. For more + information about triggers, run Get-Help New-AlarmTrigger. + .PARAMETER Enabled + Specifies if the alarm is enabled when it is created. If unset, the + default value is true. + .PARAMETER ActionRepeatMinutes + Specifies the frequency how often the actions should repeat when an alarm + does not change state. + .PARAMETER ReportingFrequency + Specifies how often the alarm is triggered, measured in minutes. A zero + value means the alarm is allowed to trigger as often as possible. A + nonzero value means that any subsequent triggers are suppressed for a + period of minutes following a reported trigger. + + If unset, the default value is 0. Allowed range is 0 - 60. + .PARAMETER ToleranceRange + Specifies the tolerance range for the metric triggers, measure in + percentage. A zero value means that the alarm triggers whenever the metric + value is above or below the specified value. A nonzero means that the + alarm triggers only after reaching a certain percentage above or below + the nominal trigger value. + + If unset, the default value is 0. Allowed range is 0 - 100. + .PARAMETER Server + Specifies the vCenter Server system on which you want to run the cmdlet. + If no value is passed to this parameter, the command runs on the default + server, $DefaultVIServer. For more information about default servers, + see the description of Connect-VIServer. + .OUTPUTS + VMware.Vim.ManagedObjectReference + .NOTES + This cmdlet requires a connection to vCenter to create the alarm action. + .LINKS + http://pubs.vmware.com/vsphere-6-0/topic/com.vmware.wssdk.apiref.doc/vim.alarm.AlarmSpec.html + .EXAMPLE + PS C:\> $trigger = New-AlarmTrigger -StateType runtime.connectionState -StateOperator isEqual -YellowStateCondition disconnected -RedStateCondition notResponding -ObjectType HostSystem + PS C:\> New-AlarmDefinition -Name 'Host Connection' -Description 'Host Connection State Alarm -Entity Datacenters -Trigger $trigger -ActionRepeatMinutes 10 + + Type Value + ---- ----- + Alarm alarm-1801 + + This will create a host connection state alarm trigger and store it in + the variable $trigger. Then it will create a new alarm 'Host Connection' + on the root level of vCenter and set the action to repeat every 10 mins. +#> + [CmdletBinding(SupportsShouldProcess = $true, ConfirmImpact = 'High')] + param ( + [Parameter(Mandatory = $true)] + [ValidateNotNullOrEmpty()] + [Alias('AlarmName')] + [string]$Name, + + [string]$Description, + + [Parameter(Mandatory = $true)] + [string]$Entity, + + [Parameter(Mandatory = $true)] + [ValidateNotNullOrEmpty()] + [VMware.Vim.AlarmExpression[]]$Trigger, + + [boolean]$Enabled = $true, + + [ValidateRange(0, 60)] + [int32]$ActionRepeatMinutes, + + [ValidateRange(0, 60)] + [int32]$ReportingFrequency = 0, + + [ValidateRange(0, 100)] + [int32]$ToleranceRange = 0, + + [string]$Server + ) + BEGIN { + Write-Verbose -Message "Adding parameters with default values to PSBoundParameters" + foreach ($Key in $MyInvocation.MyCommand.Parameters.Keys) { + $Value = Get-Variable $Key -ValueOnly -ErrorAction SilentlyContinue + if ($Value -and !$PSBoundParameters.ContainsKey($Key)) { + $PSBoundParameters[$Key] = $Value + } + } + } + PROCESS { + try { + if ($PSBoundParameters.ContainsKey('Server')) { + $Object = Get-Inventory -Name $PSBoundParameters['Entity'] -ErrorAction Stop -Server $PSBoundParameters['Server'] + $AlarmMgr = Get-View AlarmManager -ErrorAction Stop -Server $PSBoundParameters['Server'] + } else { + $Object = Get-Inventory -Name $PSBoundParameters['Entity'] -ErrorAction Stop -Server $global:DefaultVIServer + $AlarmMgr = Get-View AlarmManager -ErrorAction Stop -Server $global:DefaultVIServer + } + + if ($PSCmdlet.ShouldProcess($global:DefaultVIServer, "Create alarm $($PSBoundParameters['Name'])")) { + $Alarm = New-Object -TypeName VMware.Vim.AlarmSpec + $Alarm.Name = $PSBoundParameters['Name'] + $Alarm.Description = $PSBoundParameters['Description'] + $Alarm.Enabled = $PSBoundParameters['Enabled'] + $Alarm.Expression = New-Object -TypeName VMware.Vim.OrAlarmExpression + $Alarm.Expression.Expression += $PSBoundParameters['Trigger'] + $Alarm.Setting = New-Object -TypeName VMware.Vim.AlarmSetting + $Alarm.Setting.ReportingFrequency = $PSBoundParameters['ReportingFrequency'] * 60 + $Alarm.Setting.ToleranceRange = $PSBoundParameters['ToleranceRange'] * 100 + $Alarm.ActionFrequency = $PSBoundParameters['ActionRepeatMinutes'] * 60 + $AlarmMgr.CreateAlarm($Object.Id, $Alarm) + } + } catch { + $PSCmdlet.ThrowTerminatingError($_) + } + } +} #End of New-AlarmDefinition function + +function New-AlarmAction { +<# + .SYNOPSIS + This cmdlet creates an alarm action on the specified alarm definition. + .DESCRIPTION + This cmdlet creates an alarm action on the specified alarm definition. + This cmdlet differs from the VMware PowerCLI New-AlarmAction cmdlet as it + will create the transitions of the alarm state. It requires an alarm + action and at least one transition to be specified. + + The transition indicates when the action executes and if it repeats. + There are only four acceptable transitions: green to yellow, yellow to + red, red to yellow, and yellow to green. At least one pair must be + specified or the results will be an invalid. + + If an alarm action already exists on the alarm definition, it will be + overwritten if the same alarm action is specified. For example if the + alarm definition already has an alarm action of Snmp on the transition + of green to yellow and the cmdlet is used to create a new action of + Snmp on the transition of yellow to red, it will overwrite the existing + action and transition. The end result will be one Snmp action on the + transition of yellow to red. If you want the old to transition to remain + both should be specified during the usage of the cmdlet. + .PARAMETER AlarmDefinition + Specifies the alarm definition for which you want to configure actions. + The alarm definition can be retreived by using the Get-AlarmDefinition + cmdlet. + .PARAMETER Snmp + Indicates that a SNMP message is sent when the alarm is activated. + .PARAMETER Email + Indicates that when the alarm is activated, the system sends an email + message to the specified address. Use the Subject, To, CC, and Body + parameters to customize the alarm message. + .PARAMETER To + Specifies the email address to which you want to send a message. + .PARAMETER Cc + Specifies the email address you want to add to the CC field of the email + message. + .PARAMETER Subject + Specifies a subject for the email address message you want to send. + .PARAMETER Body + Specifies the text of the email message. + .PARAMETER GreenToYellow + Specifies the alarm action for the green to yellow transition. Allowed + values are 'Once' and 'Repeat'. If parameter is not set transition will + remain unset. + .PARAMETER YellowToRed + Specifies the alarm action for the yellow to red transition. Allowed + values are 'Once' and 'Repeat'. If parameter is not set transition will + remain unset. + .PARAMETER RedToYellow + Specifies the alarm action for the red to yellow transition. Allowed + values are 'Once' and 'Repeat'. If parameter is not set transition will + remain unset. + .PARAMETER YellowToGreen + Specifies the alarm action for the yellow to green transition. Allowed + values are 'Once' and 'Repeat'. If parameter is not set transition will + remain unset. + .NOTES + This cmdlet requires a connection to vCenter to create the alarm action. + + When using this cmdlet specify the Module-Qualified cmdlet name to avoid + using the New-AlarmAction cmdlet with VMware PowerCLI. + .EXAMPLE + PS C:\> vCenter.Alarms\New-AlarmAction -AlarmDefinition (Get-AlarmDefintion "Host CPU Usage") -Snmp -YellowToRed Repeat + + This will create an Snmp alarm action on the "Host CPU Usage" alarm + transition of yellow to red. The alarm action will also repeat, as per + the action frequency defined on the alarm. + .EXAMPLE + PS C:\> Get-AlarmDefintion "Cluster HA Status" | vCenter.Alarms\New-AlarmAction -Email -To helpdesk@company.com -GreenToYellow Once -YellowToRed Once + + This will create an Email alarm action on the "Cluster HA Status" alarm + transition of green to yellow and yellow to red. The alarm action will + send an email to vmwaresupport@wellsfarg.com one time per transition. +#> + [CmdletBinding(SupportsShouldProcess = $true, ConfirmImpact = 'Low')] + param ( + [Parameter(Mandatory = $true, ValueFromPipeline = $true)] + [VMware.VimAutomation.ViCore.Types.V1.Alarm.AlarmDefinition]$AlarmDefinition, + + [Parameter(Mandatory = $true, ParameterSetName = 'Snmp')] + [switch]$Snmp, + + [Parameter(Mandatory = $true, ParameterSetName = 'Email')] + [switch]$Email, + + [Parameter(Mandatory = $true, ParameterSetName = 'Email')] + [string[]]$To, + + [Parameter(ParameterSetName = 'Email')] + [string[]]$Cc, + + [Parameter(ParameterSetName = 'Email')] + [string]$Subject, + + [Parameter(ParameterSetName = 'Email')] + [string]$Body, + + [ValidateSet('Once', 'Repeat')] + [string]$GreenToYellow, + + [ValidateSet('Once', 'Repeat')] + [string]$YellowToRed, + + [ValidateSet('Once', 'Repeat')] + [string]$RedToYellow, + + [ValidateSet('Once', 'Repeat')] + [string]$YellowToGreen + ) + + BEGIN { + } + PROCESS { + try { + $AlarmView = Get-View -Id $PSBoundParameters['AlarmDefinition'].Id -Server ($PSBoundParameters['AlarmDefinition'].Uid.Split('@:')[1]) + $Alarm = New-Object -TypeName VMware.Vim.AlarmSpec + $Alarm.Name = $AlarmView.Info.Name + $Alarm.Description = $AlarmView.Info.Description + $Alarm.Enabled = $AlarmView.Info.Enabled + $Alarm.ActionFrequency = $AlarmView.Info.ActionFrequency + $Alarm.Action = New-Object VMware.Vim.GroupAlarmAction + $Trigger = New-Object VMware.Vim.AlarmTriggeringAction + + Write-Verbose -Message "Defining alarm actions" + if ($PSCmdlet.ParameterSetName -eq 'Snmp') { + $Trigger.Action = New-Object -TypeName VMware.Vim.SendSNMPAction + } elseif ($PSCmdlet.ParameterSetName -eq 'Email') { + $Trigger.Action = New-Object -TypeName VMware.Vim.SendEmailAction + $Trigger.Action.ToList = $PSBoundParameters['To'].GetEnumerator() | ForEach-Object -Process { + "$_;" + } + if ($PSBoundParameters.ContainsKey('Cc')) { + $Trigger.Action.CcList = $PSBoundParameters['Cc'].GetEnumerator() | ForEach-Object -Process { + "$_;" + } + } else { + $Trigger.Action.CcList = $null + } + $Trigger.Action.Subject = $PSBoundParameters['Subject'] + $Trigger.Action.Body = $PSBoundParameters['Body'] + } + + Write-Verbose -Message "Defining alarm transitions" + if ($PSBoundParameters.ContainsKey('GreenToYellow')) { + $Trans1 = New-Object -TypeName VMware.Vim.AlarmTriggeringActionTransitionSpec + $Trans1.StartState = 'green' + $Trans1.FinalState = 'yellow' + if ($PSBoundParameters['GreenToYellow'] -eq 'Repeat') { + $Trans1.Repeats = $true + } + $Trigger.TransitionSpecs += $Trans1 + } + + if ($PSBoundParameters.ContainsKey('YellowToRed')) { + $Trans2 = New-Object -TypeName VMware.Vim.AlarmTriggeringActionTransitionSpec + $Trans2.StartState = 'yellow' + $Trans2.FinalState = 'red' + if ($PSBoundParameters['YellowToRed'] -eq 'Repeat') { + $Trans2.Repeats = $true + } else { + $Trans2.Repeats = $false + } + $Trigger.TransitionSpecs += $Trans2 + } + + if ($PSBoundParameters.ContainsKey('RedToYellow')) { + $Trans3 = New-Object -TypeName VMware.Vim.AlarmTriggeringActionTransitionSpec + $Trans3.StartState = 'red' + $Trans3.FinalState = 'yellow' + if ($PSBoundParameters['RedToYellow'] -eq 'Repeat') { + $Trans3.Repeats = $true + } else { + $Trans3.Repeats = $false + } + $Trigger.TransitionSpecs += $Trans3 + } + + if ($PSBoundParameters.ContainsKey('YellowToGreen')) { + $Trans4 = New-Object -TypeName VMware.Vim.AlarmTriggeringActionTransitionSpec + $Trans4.StartState = 'yellow' + $Trans4.FinalState = 'green' + if ($PSBoundParameters['YellowToGreen'] -eq 'Repeat') { + $Trans4.Repeats = $true + } else { + $Trans4.Repeats = $false + } + $Trigger.TransitionSpecs += $Trans4 + } + + $Alarm.Action.Action += $Trigger + $Alarm.Expression = New-Object -TypeName VMware.Vim.OrAlarmExpression + $Alarm.Expression.Expression += $AlarmView.Info.Expression.Expression + $Alarm.Setting += $AlarmView.Info.Setting + $AlarmView.ReconfigureAlarm($Alarm) + } catch { + $PSCmdlet.ThrowTerminatingError($_) + } + } +} #End of New-AlarmAction function + +function New-AlarmTrigger { +<# + .SYNOPSIS + This cmdlet creates a vCenter event, state, or metric alarm trigger. + .DESCRIPTION + This cmdlet creates a vCenter event, state, or metric alarm trigger. + The trigger is used with the New-AlarmDefinition cmdlet to create a new + alarm in vCenter. This cmdlet will only create one alarm trigger. If more + triggers are required store the triggers in an array. + .PARAMETER EventType + Specifies the type of the event to trigger on. The event types can be + discovered by using the Get-EventId cmdlet. If the the event type is + 'EventEx' or 'ExtendedEvent' the EventTypeId parameter is required. + .PARAMETER EventTypeId + Specifies the id of the event type. Only used when the event type is an + 'EventEx' or 'ExtendedEvent'. + .PARAMETER Status + Specifies the status of the event. Allowed values are green, yellow, or + red. + .PARAMETER StateType + Specifies the state type to trigger on. Allowed values are + runtime.powerstate (HostSystem), summary.quickStats.guestHeartbeatStatus + (VirtualMachine), or runtime.connectionState (VirtualMachine). + .PARAMETER StateOperator + Specifies the operator condition on the target state. Allowed values are + 'isEqual' or 'isUnequal'. + .PARAMETER YellowStateCondition + Specifies the yellow state condition. When creating a state alarm + trigger at least one condition must be specified for a valid trigger to + be created. If the parameter is not set, the yellow condition is unset. + .PARAMETER RedStateCondition + Specifies the red state condition. When creating a state alarm trigger + at least one condition must be specified for a valid trigger to be + created. If the parameter is not set, the red condition is unset. + .PARAMETER MetricId + Specifies the id of the metric to trigger on. The metric ids can be + discovered by using the Get-MetricId cmdlet. + .PARAMETER MetricOperator + Specifies the operator condition on the target metric. Allowed values + are 'isAbove' or 'isBelow'. + .PARAMETER Yellow + Specifies the threshold value that triggers a yellow status. Allowed + range is 1% - 100%. + .PARAMETER YellowInterval + Specifies the time interval in minutes for which the yellow condition + must be true before the yellow status is triggered. If unset, the yellow + status is triggered immediately when the yellow condition becomes true. + .PARAMETER Red + Specifies the threshold value that triggers a red status. Allowed range + is 1% - 100%. + .PARAMETER RedInterval + Specifies the time interval in minutes for which the red condition must + be true before the red status is triggered. If unset, the red status is + triggered immediately when the red condition becomes true. + .PARAMETER ObjectType + Specifies the type of object on which the event is logged, the object + type containing the state condition or the type of object containing the + metric. + + When creating a state alarm trigger the only acceptable values are + 'HostSystem' or 'VirtualMachine'. The supported state types for each object + are as follows: + VirtualMachine type: runtime.powerState or summary.quickStats.guestHeartbeatStatus + HostSystem type: runtime.connectionState + .OUTPUTS + (Event|State|Metric)AlarmExpression + .NOTES + This cmdlet requires the PowerCLI module to be imported. + .LINK + Event Alarm Trigger + http://pubs.vmware.com/vsphere-6-0/topic/com.vmware.wssdk.apiref.doc/vim.alarm.EventAlarmExpression.html + + State Alarm Trigger + http://pubs.vmware.com/vsphere-6-0/topic/com.vmware.wssdk.apiref.doc/vim.alarm.StateAlarmExpression.html + + Metric Alarm Trigger + http://pubs.vmware.com/vsphere-6-0/topic/com.vmware.wssdk.apiref.doc/vim.alarm.MetricAlarmExpression.html + .EXAMPLE + PS C:\> New-AlarmTrigger -EventType "DasDisabledEvent" -Status Red -ObjectType ClusterComputeResource + + Comparisons : + EventType : DasDisabledEvent + ObjectType : ClusterComputeResource + Status : red + + Creates an event trigger on 'DasDisabledEvent' (HA Disabled) with a + status on 'Red'. The object type is a ClusterComputerResource because + this event occurs at a cluster level. + .EXAMPLE + PS C:\> New-AlarmTrigger -MetricId (Get-MetricId | Where Name -EQ 'cpu.usage.average').Key -Operator isAbove -Yellow 90 -YellowInterval 30 -Red 98 -RedInterval 15 -ObjectType HostSytem + + Operator : isAbove + Type : HostSytem + Metric : VMware.Vim.PerfMetricId + Yellow : 9000 + YellowInterval : 30 + Red : 9800 + RedInterval : 15 + + Creates a trigger on the 'cpu.usage.average' metric where the warning + condition must be above 90% for 30mins and the alert condition must be + above 98% for 15mins. The object type is a HostSystem. + .EXAMPLE + PS C:\temp> New-AlarmTrigger -StateType runtime.connectionState -StateOperator isEqual -YellowStateCondition Disconnected -RedStateCondition notResponding -ObjectType HostSystem + + Operator : isEqual + Type : HostSystem + StatePath : runtime.connectionState + Yellow : Disconnected + Red : notResponding + + Creates a trigger on the 'runtime.connectionState' condition where the + warning condition is 'disconnected' and the alert condition is + 'notResponding'. The object type is a HostSystem. +#> + [CmdletBinding(SupportsShouldProcess = $true, ConfirmImpact = 'Low')] + param ( + [Parameter(Mandatory = $true, ParameterSetName = 'Event')] + [string]$EventType, + + [Parameter(ParameterSetName = 'Event')] + [string]$EventTypeId, + + [Parameter(Mandatory = $true, ParameterSetName = 'Event')] + [ValidateSet('Green', 'Yellow', 'Red')] + [string]$Status, + + [Parameter(Mandatory = $true, ParameterSetName = 'State')] + [ValidateSet('runtime.powerState', 'summary.quickStats.guestHeartbeatStatus', 'runtime.connectionState')] + [string]$StateType, + + [Parameter(Mandatory = $true, ParameterSetName = 'State')] + [VMware.Vim.StateAlarmOperator]$StateOperator, + + [Parameter(ParameterSetName = 'State')] + [ValidateSet('disconnected', 'notResponding', 'connected', 'noHeartbeat', 'intermittentHeartbeat', 'poweredOn', 'poweredOff', 'suspended')] + [string]$YellowStateCondition, + + [Parameter(ParameterSetName = 'State')] + [ValidateSet('disconnected', 'notResponding', 'connected', 'noHeartbeat', 'intermittentHeartbeat', 'poweredOn', 'poweredOff', 'suspended')] + [string]$RedStateCondition, + + [Parameter(Mandatory = $true, ParameterSetName = 'Metric')] + [string]$MetricId, + + [Parameter(Mandatory = $true, ParameterSetName = 'Metric')] + [VMware.Vim.MetricAlarmOperator]$MetricOperator, + + [Parameter(ParameterSetName = 'Metric')] + [ValidateRange(1, 100)] + [int32]$Yellow, + + [Parameter(ParameterSetName = 'Metric')] + [ValidateRange(1, 90)] + [int32]$YellowInterval, + + [Parameter(ParameterSetName = 'Metric')] + [ValidateRange(1, 100)] + [int32]$Red, + + [Parameter(ParameterSetName = 'Metric')] + [ValidateRange(1, 90)] + [int32]$RedInterval, + + [Parameter(Mandatory = $true)] + [ValidateSet('ClusterComputeResource', 'Datacenter', 'Datastore', 'DistributedVirtualSwitch', 'HostSystem', 'Network', 'ResourcePool', 'VirtualMachine')] + [string]$ObjectType + ) + try { + if ($PSCmdlet.ShouldProcess("vCenter alarm", "Create $($PSCmdlet.ParameterSetName) trigger")) { + if ($PSCmdlet.ParameterSetName -eq 'Event') { + $Expression = New-Object -TypeName VMware.Vim.EventAlarmExpression + $Expression.EventType = $PSBoundParameters['EventType'] + if ($PSBoundParameters.ContainsKey('EventTypeId')) { + $Expression.EventTypeId = $PSBoundParameters['EventTypeId'] + } + $Expression.ObjectType = $PSBoundParameters['ObjectType'] + $Expression.Status = $PSBoundParameters['Status'] + $Expression + } elseif ($PSCmdlet.ParameterSetName -eq 'Metric') { + $Expression = New-Object -TypeName VMware.Vim.MetricAlarmExpression + $Expression.Metric = New-Object -TypeName VMware.Vim.PerfMetricId + $Expression.Metric.CounterId = $PSBoundParameters['MetricId'] + $Expression.Metric.Instance = "" + $Expression.Operator = $PSBoundParameters['MetricOperator'] + $Expression.Red = ($PSBoundParameters['Red'] * 100) + $Expression.RedInterval = ($PSBoundParameters['RedInterval'] * 60) + $Expression.Yellow = ($PSBoundParameters['Yellow'] * 100) + $Expression.YellowInterval = ($PSBoundParameters['YellowInterval'] * 60) + $Expression.Type = $PSBoundParameters['ObjectType'] + $Expression + } elseif ($PSCmdlet.ParameterSetName -eq 'State') { + $Expression = New-Object -TypeName VMware.Vim.StateAlarmExpression + $Expression.Operator = $PSBoundParameters['StateOperator'] + $Expression.Type = $PSBoundParameters['ObjectType'] + $Expression.StatePath = $PSBoundParameters['StateType'] + + if ($PSBoundParameters.ContainsKey('RedStateCondition')) { + if ($PSBoundParameters['RedStateCondition'] -eq 'intermittentHeartbeat') { + $Expression.Red = 'yellow' + } elseif ($PSBoundParameters['RedStateCondition'] -eq 'noHeartbeat') { + $Expression.Red = 'red' + } else { + $Expression.Red = $PSBoundParameters['RedStateCondition'] + } + } + + if ($PSBoundParameters.ContainsKey('YellowStateCondition')) { + if ($PSBoundParameters['YellowStateCondition'] -eq 'intermittentHeartbeat') { + $Expression.Yellow = 'yellow' + } elseif ($PSBoundParameters['YellowStateCondition'] -eq 'noHeartbeat') { + $Expression.Yellow = 'red' + } else { + $Expression.Yellow = $PSBoundParameters['YellowStateCondition'] + } + } + $Expression + } + } + } catch { + $PSCmdlet.ThrowTerminatingError($_) + } +} #End of New-AlarmTrigger function + +function Get-MetricId { +<# + .SYNOPSIS + This cmdlet collects all of the available metrics from vCenter. + .DESCRIPTION + This cmdlet collects all of the available metrics from vCenter. It will + provide the metric name, key, stats level, and summary of the metric. + The information can be used to identify the available metrics on vCenter + as well as gathering the metric key needed for configuring an alarm. + + The metric keys are unique across vCenters. If you are connected to + more than one vCenter metrics from each vCenter will be generated. A + vCenter property is available to help determine the correct metric key + on a given vCenter. This is extrememly useful when trying to create + a metric based vCenter alarm. + .PARAMETER MetricGroup + Specifies the name of the metric group you would like to see. Allowed + values are 'CPU', 'Mem', 'Disk', 'Net', and 'Datastore'. + .OUTPUTS + System.Management.Automation.PSCustomObject + .NOTES + This cmdlet requires a connection to vCenter to collect metric data. + .EXAMPLE + PS C:\> Get-MetricId -MetricGroup Mem + + Name : mem.usage.none + Key : 23 + Level : 4 + Summary : Memory usage as percentage of total configured or available memory + vCenter : vCenter01 + + Name : mem.usage.average + Key : 24 + Level : 1 + Summary : Memory usage as percentage of total configured or available memory + vCenter : vCenter01 + + Name : mem.usage.minimum + Key : 25 + Level : 4 + Summary : Memory usage as percentage of total configured or available memory + vCenter : vCenter01 + ..... + + Collects all of the available memory metrics on the connected vCenter. +#> + [CmdletBinding()] + param ( + [ValidateSet('CPU', 'Mem', 'Disk', 'Net', 'Datastore')] + [string]$MetricGroup + ) + + foreach ($Mgr in (Get-View PerformanceManager-PerfMgr)) { + $vCenter = $Mgr.Client.ServiceUrl.Split('/')[2] + if ($PSBoundParameters.ContainsKey('MetricGroup')) { + $Metrics += $Mgr.PerfCounter | Where-Object -FilterScript { + $_.GroupInfo.Key -eq $PSBoundParameters['MetricGroup'] + } + } else { + $Metrics += $Mgr.PerfCounter + } + + $Metrics | ForEach-Object -Process { + [pscustomobject] @{ + Name = $_.GroupInfo.Key + "." + $_.NameInfo.key + "." + $_.RollupType + Key = $_.Key + Level = $_.Level + Summary = $_.NameInfo.Summary + vCenter = $vCenter + } + } + } +} #End of Get-MetricId function + +function Get-EventId { +<# + .SYNOPSIS + This cmdlet collects all of the available events from vCenter. + .DESCRIPTION + This cmdlet collects all of the available events from vCenter. It will + provide the event type, event type id (if applicable), category, + description, and summary of the event. The information can be used to + identify the available events on vCenter as well as gathering the event + type and event type id (if applicable) required for configuring an alarm. + + If the event type is 'EventEx' or 'ExtendedEvent' both the event type + and event type id will be required to create a new event based vCenter + alarm. + + The event types can be unique across vCenters. If you are connected to + more than one vCenter events from each vCenter will be generated. A + vCenter property is available to help determine the correct event type + on a given vCenter. This is extrememly useful when trying to create + a event based vCenter alarm. + .PARAMETER Category + Specifies the name of the event category you would like to see. Allowed + values are 'info', 'warning', 'error', and 'user'. + .OUTPUTS + System.Management.Automation.PSCustomObject + .NOTES + This cmdlet requires a connection to vCenter to collect event data. + .EXAMPLE + PS C:\> Get-EventId -Category Error + + EventType : ExtendedEvent + EventTypeId : ad.event.ImportCertFailedEvent + Category : error + Description : Import certificate failure + FullFormat : Import certificate failed. + vCenter : vCenter01 + + EventType : ExtendedEvent + EventTypeId : ad.event.JoinDomainFailedEvent + Category : error + Description : Join domain failure + FullFormat : Join domain failed. + vCenter : vCenter01 + + EventType : ExtendedEvent + EventTypeId : ad.event.LeaveDomainFailedEvent + Category : error + Description : Leave domain failure + FullFormat : Leave domain failed. + vCenter : vCenter01 + ..... +#> + [CmdletBinding()] + param ( + [VMware.Vim.EventCategory]$Category + ) + + foreach ($Mgr in (Get-View EventManager)) { + $vCenter = $Mgr.Client.ServiceUrl.Split('/')[2] + if ($PSBoundParameters.ContainsKey('Category')) { + $Events += $Mgr.Description.EventInfo | Where-Object -FilterScript { + $_.Category -eq $PSBoundParameters['Category'] + } + } else { + $Events += $Mgr.Description.EventInfo + } + + $Events | ForEach-Object -Process { + $Hash = [ordered]@{} + $Hash.Add('EventType', $_.Key) + if ($_.Key -eq 'ExtendedEvent' -or $_.Key -eq 'EventEx') { + $Hash.Add('EventTypeId', $_.FullFormat.Split('|')[0]) + } + $Hash.Add('Category', $_.Category) + $Hash.Add('Description', $_.Description) + if ($Hash['EventType'] -eq 'ExtendedEvent' -or $Hash['EventType'] -eq 'EventEx') { + $Hash.Add('FullFormat', $_.FullFormat.Split('|')[1]) + } else { + $Hash.Add('FullFormat', $_.FullFormat) + } + $Hash.Add('vCenter', $vCenter) + New-Object -TypeName System.Management.Automation.PSObject -Property $Hash + } + } +} #End of Get-EventId function \ No newline at end of file From 16530f256d10f242b1daa0d61b2b5ce32e534ce7 Mon Sep 17 00:00:00 2001 From: jrob24 Date: Thu, 21 Sep 2017 23:31:44 -0500 Subject: [PATCH 02/29] Delete vCenter.Alarms.psm1 --- Modules/vCenter.Alarms/vCenter.Alarms.psm1 | 736 --------------------- 1 file changed, 736 deletions(-) delete mode 100644 Modules/vCenter.Alarms/vCenter.Alarms.psm1 diff --git a/Modules/vCenter.Alarms/vCenter.Alarms.psm1 b/Modules/vCenter.Alarms/vCenter.Alarms.psm1 deleted file mode 100644 index 80d625f..0000000 --- a/Modules/vCenter.Alarms/vCenter.Alarms.psm1 +++ /dev/null @@ -1,736 +0,0 @@ -<# - =========================================================================== - Created by: Jason Robinson - Created on: 05/2017 - Twitter: @jrob24 - =========================================================================== - .DESCRIPTION - PowerShell Module to help with creation of vCenter Alarms - .NOTES - See New-vCenterAlarms.ps1 for examples of alarm creation - - * Tested against PowerShell 5.0 - * Tested against PowerCLI 6.5.1 build 5377412 - * Tested against vCenter 6.0 - * Tested against ESXi 5.5/6.0 -#> - -function New-AlarmDefinition { -<# - .SYNOPSIS - This cmdlet creates a new alarm defintion on the specified entity in vCenter. - .DESCRIPTION - This cmdlet creates a new alarm defintion on the specified entity in vCenter. - An alarm trigger is required in order to create a new alarm definition. - They can be created by using the New-AlarmTrigger cmdlet. - - After the alarm definition is created, if alarm actions are required use - the cmdlet New-AlarmAction to create actions for the alarm. - .PARAMETER Name - Specifies the name of the alarm you want to create. - .PARAMETER Description - Specifies the description for the alarm. - .PARAMETER Entity - Specifies where to create the alarm. To create the alarm at the root - level of vCenter use the entity 'Datacenters', otherwise specify any - object name. - .PARAMETER Trigger - Specifies the alarm event, state, or metric trigger(s). The alarm - trigger(s) are created with the New-AlarmTrigger cmdlet. For more - information about triggers, run Get-Help New-AlarmTrigger. - .PARAMETER Enabled - Specifies if the alarm is enabled when it is created. If unset, the - default value is true. - .PARAMETER ActionRepeatMinutes - Specifies the frequency how often the actions should repeat when an alarm - does not change state. - .PARAMETER ReportingFrequency - Specifies how often the alarm is triggered, measured in minutes. A zero - value means the alarm is allowed to trigger as often as possible. A - nonzero value means that any subsequent triggers are suppressed for a - period of minutes following a reported trigger. - - If unset, the default value is 0. Allowed range is 0 - 60. - .PARAMETER ToleranceRange - Specifies the tolerance range for the metric triggers, measure in - percentage. A zero value means that the alarm triggers whenever the metric - value is above or below the specified value. A nonzero means that the - alarm triggers only after reaching a certain percentage above or below - the nominal trigger value. - - If unset, the default value is 0. Allowed range is 0 - 100. - .PARAMETER Server - Specifies the vCenter Server system on which you want to run the cmdlet. - If no value is passed to this parameter, the command runs on the default - server, $DefaultVIServer. For more information about default servers, - see the description of Connect-VIServer. - .OUTPUTS - VMware.Vim.ManagedObjectReference - .NOTES - This cmdlet requires a connection to vCenter to create the alarm action. - .LINKS - http://pubs.vmware.com/vsphere-6-0/topic/com.vmware.wssdk.apiref.doc/vim.alarm.AlarmSpec.html - .EXAMPLE - PS C:\> $trigger = New-AlarmTrigger -StateType runtime.connectionState -StateOperator isEqual -YellowStateCondition disconnected -RedStateCondition notResponding -ObjectType HostSystem - PS C:\> New-AlarmDefinition -Name 'Host Connection' -Description 'Host Connection State Alarm -Entity Datacenters -Trigger $trigger -ActionRepeatMinutes 10 - - Type Value - ---- ----- - Alarm alarm-1801 - - This will create a host connection state alarm trigger and store it in - the variable $trigger. Then it will create a new alarm 'Host Connection' - on the root level of vCenter and set the action to repeat every 10 mins. -#> - [CmdletBinding(SupportsShouldProcess = $true, ConfirmImpact = 'High')] - param ( - [Parameter(Mandatory = $true)] - [ValidateNotNullOrEmpty()] - [Alias('AlarmName')] - [string]$Name, - - [string]$Description, - - [Parameter(Mandatory = $true)] - [string]$Entity, - - [Parameter(Mandatory = $true)] - [ValidateNotNullOrEmpty()] - [VMware.Vim.AlarmExpression[]]$Trigger, - - [boolean]$Enabled = $true, - - [ValidateRange(0, 60)] - [int32]$ActionRepeatMinutes, - - [ValidateRange(0, 60)] - [int32]$ReportingFrequency = 0, - - [ValidateRange(0, 100)] - [int32]$ToleranceRange = 0, - - [string]$Server - ) - BEGIN { - Write-Verbose -Message "Adding parameters with default values to PSBoundParameters" - foreach ($Key in $MyInvocation.MyCommand.Parameters.Keys) { - $Value = Get-Variable $Key -ValueOnly -ErrorAction SilentlyContinue - if ($Value -and !$PSBoundParameters.ContainsKey($Key)) { - $PSBoundParameters[$Key] = $Value - } - } - } - PROCESS { - try { - if ($PSBoundParameters.ContainsKey('Server')) { - $Object = Get-Inventory -Name $PSBoundParameters['Entity'] -ErrorAction Stop -Server $PSBoundParameters['Server'] - $AlarmMgr = Get-View AlarmManager -ErrorAction Stop -Server $PSBoundParameters['Server'] - } else { - $Object = Get-Inventory -Name $PSBoundParameters['Entity'] -ErrorAction Stop -Server $global:DefaultVIServer - $AlarmMgr = Get-View AlarmManager -ErrorAction Stop -Server $global:DefaultVIServer - } - - if ($PSCmdlet.ShouldProcess($global:DefaultVIServer, "Create alarm $($PSBoundParameters['Name'])")) { - $Alarm = New-Object -TypeName VMware.Vim.AlarmSpec - $Alarm.Name = $PSBoundParameters['Name'] - $Alarm.Description = $PSBoundParameters['Description'] - $Alarm.Enabled = $PSBoundParameters['Enabled'] - $Alarm.Expression = New-Object -TypeName VMware.Vim.OrAlarmExpression - $Alarm.Expression.Expression += $PSBoundParameters['Trigger'] - $Alarm.Setting = New-Object -TypeName VMware.Vim.AlarmSetting - $Alarm.Setting.ReportingFrequency = $PSBoundParameters['ReportingFrequency'] * 60 - $Alarm.Setting.ToleranceRange = $PSBoundParameters['ToleranceRange'] * 100 - $Alarm.ActionFrequency = $PSBoundParameters['ActionRepeatMinutes'] * 60 - $AlarmMgr.CreateAlarm($Object.Id, $Alarm) - } - } catch { - $PSCmdlet.ThrowTerminatingError($_) - } - } -} #End of New-AlarmDefinition function - -function New-AlarmAction { -<# - .SYNOPSIS - This cmdlet creates an alarm action on the specified alarm definition. - .DESCRIPTION - This cmdlet creates an alarm action on the specified alarm definition. - This cmdlet differs from the VMware PowerCLI New-AlarmAction cmdlet as it - will create the transitions of the alarm state. It requires an alarm - action and at least one transition to be specified. - - The transition indicates when the action executes and if it repeats. - There are only four acceptable transitions: green to yellow, yellow to - red, red to yellow, and yellow to green. At least one pair must be - specified or the results will be an invalid. - - If an alarm action already exists on the alarm definition, it will be - overwritten if the same alarm action is specified. For example if the - alarm definition already has an alarm action of Snmp on the transition - of green to yellow and the cmdlet is used to create a new action of - Snmp on the transition of yellow to red, it will overwrite the existing - action and transition. The end result will be one Snmp action on the - transition of yellow to red. If you want the old to transition to remain - both should be specified during the usage of the cmdlet. - .PARAMETER AlarmDefinition - Specifies the alarm definition for which you want to configure actions. - The alarm definition can be retreived by using the Get-AlarmDefinition - cmdlet. - .PARAMETER Snmp - Indicates that a SNMP message is sent when the alarm is activated. - .PARAMETER Email - Indicates that when the alarm is activated, the system sends an email - message to the specified address. Use the Subject, To, CC, and Body - parameters to customize the alarm message. - .PARAMETER To - Specifies the email address to which you want to send a message. - .PARAMETER Cc - Specifies the email address you want to add to the CC field of the email - message. - .PARAMETER Subject - Specifies a subject for the email address message you want to send. - .PARAMETER Body - Specifies the text of the email message. - .PARAMETER GreenToYellow - Specifies the alarm action for the green to yellow transition. Allowed - values are 'Once' and 'Repeat'. If parameter is not set transition will - remain unset. - .PARAMETER YellowToRed - Specifies the alarm action for the yellow to red transition. Allowed - values are 'Once' and 'Repeat'. If parameter is not set transition will - remain unset. - .PARAMETER RedToYellow - Specifies the alarm action for the red to yellow transition. Allowed - values are 'Once' and 'Repeat'. If parameter is not set transition will - remain unset. - .PARAMETER YellowToGreen - Specifies the alarm action for the yellow to green transition. Allowed - values are 'Once' and 'Repeat'. If parameter is not set transition will - remain unset. - .NOTES - This cmdlet requires a connection to vCenter to create the alarm action. - - When using this cmdlet specify the Module-Qualified cmdlet name to avoid - using the New-AlarmAction cmdlet with VMware PowerCLI. - .EXAMPLE - PS C:\> vCenter.Alarms\New-AlarmAction -AlarmDefinition (Get-AlarmDefintion "Host CPU Usage") -Snmp -YellowToRed Repeat - - This will create an Snmp alarm action on the "Host CPU Usage" alarm - transition of yellow to red. The alarm action will also repeat, as per - the action frequency defined on the alarm. - .EXAMPLE - PS C:\> Get-AlarmDefintion "Cluster HA Status" | vCenter.Alarms\New-AlarmAction -Email -To helpdesk@company.com -GreenToYellow Once -YellowToRed Once - - This will create an Email alarm action on the "Cluster HA Status" alarm - transition of green to yellow and yellow to red. The alarm action will - send an email to vmwaresupport@wellsfarg.com one time per transition. -#> - [CmdletBinding(SupportsShouldProcess = $true, ConfirmImpact = 'Low')] - param ( - [Parameter(Mandatory = $true, ValueFromPipeline = $true)] - [VMware.VimAutomation.ViCore.Types.V1.Alarm.AlarmDefinition]$AlarmDefinition, - - [Parameter(Mandatory = $true, ParameterSetName = 'Snmp')] - [switch]$Snmp, - - [Parameter(Mandatory = $true, ParameterSetName = 'Email')] - [switch]$Email, - - [Parameter(Mandatory = $true, ParameterSetName = 'Email')] - [string[]]$To, - - [Parameter(ParameterSetName = 'Email')] - [string[]]$Cc, - - [Parameter(ParameterSetName = 'Email')] - [string]$Subject, - - [Parameter(ParameterSetName = 'Email')] - [string]$Body, - - [ValidateSet('Once', 'Repeat')] - [string]$GreenToYellow, - - [ValidateSet('Once', 'Repeat')] - [string]$YellowToRed, - - [ValidateSet('Once', 'Repeat')] - [string]$RedToYellow, - - [ValidateSet('Once', 'Repeat')] - [string]$YellowToGreen - ) - - BEGIN { - } - PROCESS { - try { - $AlarmView = Get-View -Id $PSBoundParameters['AlarmDefinition'].Id -Server ($PSBoundParameters['AlarmDefinition'].Uid.Split('@:')[1]) - $Alarm = New-Object -TypeName VMware.Vim.AlarmSpec - $Alarm.Name = $AlarmView.Info.Name - $Alarm.Description = $AlarmView.Info.Description - $Alarm.Enabled = $AlarmView.Info.Enabled - $Alarm.ActionFrequency = $AlarmView.Info.ActionFrequency - $Alarm.Action = New-Object VMware.Vim.GroupAlarmAction - $Trigger = New-Object VMware.Vim.AlarmTriggeringAction - - Write-Verbose -Message "Defining alarm actions" - if ($PSCmdlet.ParameterSetName -eq 'Snmp') { - $Trigger.Action = New-Object -TypeName VMware.Vim.SendSNMPAction - } elseif ($PSCmdlet.ParameterSetName -eq 'Email') { - $Trigger.Action = New-Object -TypeName VMware.Vim.SendEmailAction - $Trigger.Action.ToList = $PSBoundParameters['To'].GetEnumerator() | ForEach-Object -Process { - "$_;" - } - if ($PSBoundParameters.ContainsKey('Cc')) { - $Trigger.Action.CcList = $PSBoundParameters['Cc'].GetEnumerator() | ForEach-Object -Process { - "$_;" - } - } else { - $Trigger.Action.CcList = $null - } - $Trigger.Action.Subject = $PSBoundParameters['Subject'] - $Trigger.Action.Body = $PSBoundParameters['Body'] - } - - Write-Verbose -Message "Defining alarm transitions" - if ($PSBoundParameters.ContainsKey('GreenToYellow')) { - $Trans1 = New-Object -TypeName VMware.Vim.AlarmTriggeringActionTransitionSpec - $Trans1.StartState = 'green' - $Trans1.FinalState = 'yellow' - if ($PSBoundParameters['GreenToYellow'] -eq 'Repeat') { - $Trans1.Repeats = $true - } - $Trigger.TransitionSpecs += $Trans1 - } - - if ($PSBoundParameters.ContainsKey('YellowToRed')) { - $Trans2 = New-Object -TypeName VMware.Vim.AlarmTriggeringActionTransitionSpec - $Trans2.StartState = 'yellow' - $Trans2.FinalState = 'red' - if ($PSBoundParameters['YellowToRed'] -eq 'Repeat') { - $Trans2.Repeats = $true - } else { - $Trans2.Repeats = $false - } - $Trigger.TransitionSpecs += $Trans2 - } - - if ($PSBoundParameters.ContainsKey('RedToYellow')) { - $Trans3 = New-Object -TypeName VMware.Vim.AlarmTriggeringActionTransitionSpec - $Trans3.StartState = 'red' - $Trans3.FinalState = 'yellow' - if ($PSBoundParameters['RedToYellow'] -eq 'Repeat') { - $Trans3.Repeats = $true - } else { - $Trans3.Repeats = $false - } - $Trigger.TransitionSpecs += $Trans3 - } - - if ($PSBoundParameters.ContainsKey('YellowToGreen')) { - $Trans4 = New-Object -TypeName VMware.Vim.AlarmTriggeringActionTransitionSpec - $Trans4.StartState = 'yellow' - $Trans4.FinalState = 'green' - if ($PSBoundParameters['YellowToGreen'] -eq 'Repeat') { - $Trans4.Repeats = $true - } else { - $Trans4.Repeats = $false - } - $Trigger.TransitionSpecs += $Trans4 - } - - $Alarm.Action.Action += $Trigger - $Alarm.Expression = New-Object -TypeName VMware.Vim.OrAlarmExpression - $Alarm.Expression.Expression += $AlarmView.Info.Expression.Expression - $Alarm.Setting += $AlarmView.Info.Setting - $AlarmView.ReconfigureAlarm($Alarm) - } catch { - $PSCmdlet.ThrowTerminatingError($_) - } - } -} #End of New-AlarmAction function - -function New-AlarmTrigger { -<# - .SYNOPSIS - This cmdlet creates a vCenter event, state, or metric alarm trigger. - .DESCRIPTION - This cmdlet creates a vCenter event, state, or metric alarm trigger. - The trigger is used with the New-AlarmDefinition cmdlet to create a new - alarm in vCenter. This cmdlet will only create one alarm trigger. If more - triggers are required store the triggers in an array. - .PARAMETER EventType - Specifies the type of the event to trigger on. The event types can be - discovered by using the Get-EventId cmdlet. If the the event type is - 'EventEx' or 'ExtendedEvent' the EventTypeId parameter is required. - .PARAMETER EventTypeId - Specifies the id of the event type. Only used when the event type is an - 'EventEx' or 'ExtendedEvent'. - .PARAMETER Status - Specifies the status of the event. Allowed values are green, yellow, or - red. - .PARAMETER StateType - Specifies the state type to trigger on. Allowed values are - runtime.powerstate (HostSystem), summary.quickStats.guestHeartbeatStatus - (VirtualMachine), or runtime.connectionState (VirtualMachine). - .PARAMETER StateOperator - Specifies the operator condition on the target state. Allowed values are - 'isEqual' or 'isUnequal'. - .PARAMETER YellowStateCondition - Specifies the yellow state condition. When creating a state alarm - trigger at least one condition must be specified for a valid trigger to - be created. If the parameter is not set, the yellow condition is unset. - .PARAMETER RedStateCondition - Specifies the red state condition. When creating a state alarm trigger - at least one condition must be specified for a valid trigger to be - created. If the parameter is not set, the red condition is unset. - .PARAMETER MetricId - Specifies the id of the metric to trigger on. The metric ids can be - discovered by using the Get-MetricId cmdlet. - .PARAMETER MetricOperator - Specifies the operator condition on the target metric. Allowed values - are 'isAbove' or 'isBelow'. - .PARAMETER Yellow - Specifies the threshold value that triggers a yellow status. Allowed - range is 1% - 100%. - .PARAMETER YellowInterval - Specifies the time interval in minutes for which the yellow condition - must be true before the yellow status is triggered. If unset, the yellow - status is triggered immediately when the yellow condition becomes true. - .PARAMETER Red - Specifies the threshold value that triggers a red status. Allowed range - is 1% - 100%. - .PARAMETER RedInterval - Specifies the time interval in minutes for which the red condition must - be true before the red status is triggered. If unset, the red status is - triggered immediately when the red condition becomes true. - .PARAMETER ObjectType - Specifies the type of object on which the event is logged, the object - type containing the state condition or the type of object containing the - metric. - - When creating a state alarm trigger the only acceptable values are - 'HostSystem' or 'VirtualMachine'. The supported state types for each object - are as follows: - VirtualMachine type: runtime.powerState or summary.quickStats.guestHeartbeatStatus - HostSystem type: runtime.connectionState - .OUTPUTS - (Event|State|Metric)AlarmExpression - .NOTES - This cmdlet requires the PowerCLI module to be imported. - .LINK - Event Alarm Trigger - http://pubs.vmware.com/vsphere-6-0/topic/com.vmware.wssdk.apiref.doc/vim.alarm.EventAlarmExpression.html - - State Alarm Trigger - http://pubs.vmware.com/vsphere-6-0/topic/com.vmware.wssdk.apiref.doc/vim.alarm.StateAlarmExpression.html - - Metric Alarm Trigger - http://pubs.vmware.com/vsphere-6-0/topic/com.vmware.wssdk.apiref.doc/vim.alarm.MetricAlarmExpression.html - .EXAMPLE - PS C:\> New-AlarmTrigger -EventType "DasDisabledEvent" -Status Red -ObjectType ClusterComputeResource - - Comparisons : - EventType : DasDisabledEvent - ObjectType : ClusterComputeResource - Status : red - - Creates an event trigger on 'DasDisabledEvent' (HA Disabled) with a - status on 'Red'. The object type is a ClusterComputerResource because - this event occurs at a cluster level. - .EXAMPLE - PS C:\> New-AlarmTrigger -MetricId (Get-MetricId | Where Name -EQ 'cpu.usage.average').Key -Operator isAbove -Yellow 90 -YellowInterval 30 -Red 98 -RedInterval 15 -ObjectType HostSytem - - Operator : isAbove - Type : HostSytem - Metric : VMware.Vim.PerfMetricId - Yellow : 9000 - YellowInterval : 30 - Red : 9800 - RedInterval : 15 - - Creates a trigger on the 'cpu.usage.average' metric where the warning - condition must be above 90% for 30mins and the alert condition must be - above 98% for 15mins. The object type is a HostSystem. - .EXAMPLE - PS C:\temp> New-AlarmTrigger -StateType runtime.connectionState -StateOperator isEqual -YellowStateCondition Disconnected -RedStateCondition notResponding -ObjectType HostSystem - - Operator : isEqual - Type : HostSystem - StatePath : runtime.connectionState - Yellow : Disconnected - Red : notResponding - - Creates a trigger on the 'runtime.connectionState' condition where the - warning condition is 'disconnected' and the alert condition is - 'notResponding'. The object type is a HostSystem. -#> - [CmdletBinding(SupportsShouldProcess = $true, ConfirmImpact = 'Low')] - param ( - [Parameter(Mandatory = $true, ParameterSetName = 'Event')] - [string]$EventType, - - [Parameter(ParameterSetName = 'Event')] - [string]$EventTypeId, - - [Parameter(Mandatory = $true, ParameterSetName = 'Event')] - [ValidateSet('Green', 'Yellow', 'Red')] - [string]$Status, - - [Parameter(Mandatory = $true, ParameterSetName = 'State')] - [ValidateSet('runtime.powerState', 'summary.quickStats.guestHeartbeatStatus', 'runtime.connectionState')] - [string]$StateType, - - [Parameter(Mandatory = $true, ParameterSetName = 'State')] - [VMware.Vim.StateAlarmOperator]$StateOperator, - - [Parameter(ParameterSetName = 'State')] - [ValidateSet('disconnected', 'notResponding', 'connected', 'noHeartbeat', 'intermittentHeartbeat', 'poweredOn', 'poweredOff', 'suspended')] - [string]$YellowStateCondition, - - [Parameter(ParameterSetName = 'State')] - [ValidateSet('disconnected', 'notResponding', 'connected', 'noHeartbeat', 'intermittentHeartbeat', 'poweredOn', 'poweredOff', 'suspended')] - [string]$RedStateCondition, - - [Parameter(Mandatory = $true, ParameterSetName = 'Metric')] - [string]$MetricId, - - [Parameter(Mandatory = $true, ParameterSetName = 'Metric')] - [VMware.Vim.MetricAlarmOperator]$MetricOperator, - - [Parameter(ParameterSetName = 'Metric')] - [ValidateRange(1, 100)] - [int32]$Yellow, - - [Parameter(ParameterSetName = 'Metric')] - [ValidateRange(1, 90)] - [int32]$YellowInterval, - - [Parameter(ParameterSetName = 'Metric')] - [ValidateRange(1, 100)] - [int32]$Red, - - [Parameter(ParameterSetName = 'Metric')] - [ValidateRange(1, 90)] - [int32]$RedInterval, - - [Parameter(Mandatory = $true)] - [ValidateSet('ClusterComputeResource', 'Datacenter', 'Datastore', 'DistributedVirtualSwitch', 'HostSystem', 'Network', 'ResourcePool', 'VirtualMachine')] - [string]$ObjectType - ) - try { - if ($PSCmdlet.ShouldProcess("vCenter alarm", "Create $($PSCmdlet.ParameterSetName) trigger")) { - if ($PSCmdlet.ParameterSetName -eq 'Event') { - $Expression = New-Object -TypeName VMware.Vim.EventAlarmExpression - $Expression.EventType = $PSBoundParameters['EventType'] - if ($PSBoundParameters.ContainsKey('EventTypeId')) { - $Expression.EventTypeId = $PSBoundParameters['EventTypeId'] - } - $Expression.ObjectType = $PSBoundParameters['ObjectType'] - $Expression.Status = $PSBoundParameters['Status'] - $Expression - } elseif ($PSCmdlet.ParameterSetName -eq 'Metric') { - $Expression = New-Object -TypeName VMware.Vim.MetricAlarmExpression - $Expression.Metric = New-Object -TypeName VMware.Vim.PerfMetricId - $Expression.Metric.CounterId = $PSBoundParameters['MetricId'] - $Expression.Metric.Instance = "" - $Expression.Operator = $PSBoundParameters['MetricOperator'] - $Expression.Red = ($PSBoundParameters['Red'] * 100) - $Expression.RedInterval = ($PSBoundParameters['RedInterval'] * 60) - $Expression.Yellow = ($PSBoundParameters['Yellow'] * 100) - $Expression.YellowInterval = ($PSBoundParameters['YellowInterval'] * 60) - $Expression.Type = $PSBoundParameters['ObjectType'] - $Expression - } elseif ($PSCmdlet.ParameterSetName -eq 'State') { - $Expression = New-Object -TypeName VMware.Vim.StateAlarmExpression - $Expression.Operator = $PSBoundParameters['StateOperator'] - $Expression.Type = $PSBoundParameters['ObjectType'] - $Expression.StatePath = $PSBoundParameters['StateType'] - - if ($PSBoundParameters.ContainsKey('RedStateCondition')) { - if ($PSBoundParameters['RedStateCondition'] -eq 'intermittentHeartbeat') { - $Expression.Red = 'yellow' - } elseif ($PSBoundParameters['RedStateCondition'] -eq 'noHeartbeat') { - $Expression.Red = 'red' - } else { - $Expression.Red = $PSBoundParameters['RedStateCondition'] - } - } - - if ($PSBoundParameters.ContainsKey('YellowStateCondition')) { - if ($PSBoundParameters['YellowStateCondition'] -eq 'intermittentHeartbeat') { - $Expression.Yellow = 'yellow' - } elseif ($PSBoundParameters['YellowStateCondition'] -eq 'noHeartbeat') { - $Expression.Yellow = 'red' - } else { - $Expression.Yellow = $PSBoundParameters['YellowStateCondition'] - } - } - $Expression - } - } - } catch { - $PSCmdlet.ThrowTerminatingError($_) - } -} #End of New-AlarmTrigger function - -function Get-MetricId { -<# - .SYNOPSIS - This cmdlet collects all of the available metrics from vCenter. - .DESCRIPTION - This cmdlet collects all of the available metrics from vCenter. It will - provide the metric name, key, stats level, and summary of the metric. - The information can be used to identify the available metrics on vCenter - as well as gathering the metric key needed for configuring an alarm. - - The metric keys are unique across vCenters. If you are connected to - more than one vCenter metrics from each vCenter will be generated. A - vCenter property is available to help determine the correct metric key - on a given vCenter. This is extrememly useful when trying to create - a metric based vCenter alarm. - .PARAMETER MetricGroup - Specifies the name of the metric group you would like to see. Allowed - values are 'CPU', 'Mem', 'Disk', 'Net', and 'Datastore'. - .OUTPUTS - System.Management.Automation.PSCustomObject - .NOTES - This cmdlet requires a connection to vCenter to collect metric data. - .EXAMPLE - PS C:\> Get-MetricId -MetricGroup Mem - - Name : mem.usage.none - Key : 23 - Level : 4 - Summary : Memory usage as percentage of total configured or available memory - vCenter : vCenter01 - - Name : mem.usage.average - Key : 24 - Level : 1 - Summary : Memory usage as percentage of total configured or available memory - vCenter : vCenter01 - - Name : mem.usage.minimum - Key : 25 - Level : 4 - Summary : Memory usage as percentage of total configured or available memory - vCenter : vCenter01 - ..... - - Collects all of the available memory metrics on the connected vCenter. -#> - [CmdletBinding()] - param ( - [ValidateSet('CPU', 'Mem', 'Disk', 'Net', 'Datastore')] - [string]$MetricGroup - ) - - foreach ($Mgr in (Get-View PerformanceManager-PerfMgr)) { - $vCenter = $Mgr.Client.ServiceUrl.Split('/')[2] - if ($PSBoundParameters.ContainsKey('MetricGroup')) { - $Metrics += $Mgr.PerfCounter | Where-Object -FilterScript { - $_.GroupInfo.Key -eq $PSBoundParameters['MetricGroup'] - } - } else { - $Metrics += $Mgr.PerfCounter - } - - $Metrics | ForEach-Object -Process { - [pscustomobject] @{ - Name = $_.GroupInfo.Key + "." + $_.NameInfo.key + "." + $_.RollupType - Key = $_.Key - Level = $_.Level - Summary = $_.NameInfo.Summary - vCenter = $vCenter - } - } - } -} #End of Get-MetricId function - -function Get-EventId { -<# - .SYNOPSIS - This cmdlet collects all of the available events from vCenter. - .DESCRIPTION - This cmdlet collects all of the available events from vCenter. It will - provide the event type, event type id (if applicable), category, - description, and summary of the event. The information can be used to - identify the available events on vCenter as well as gathering the event - type and event type id (if applicable) required for configuring an alarm. - - If the event type is 'EventEx' or 'ExtendedEvent' both the event type - and event type id will be required to create a new event based vCenter - alarm. - - The event types can be unique across vCenters. If you are connected to - more than one vCenter events from each vCenter will be generated. A - vCenter property is available to help determine the correct event type - on a given vCenter. This is extrememly useful when trying to create - a event based vCenter alarm. - .PARAMETER Category - Specifies the name of the event category you would like to see. Allowed - values are 'info', 'warning', 'error', and 'user'. - .OUTPUTS - System.Management.Automation.PSCustomObject - .NOTES - This cmdlet requires a connection to vCenter to collect event data. - .EXAMPLE - PS C:\> Get-EventId -Category Error - - EventType : ExtendedEvent - EventTypeId : ad.event.ImportCertFailedEvent - Category : error - Description : Import certificate failure - FullFormat : Import certificate failed. - vCenter : vCenter01 - - EventType : ExtendedEvent - EventTypeId : ad.event.JoinDomainFailedEvent - Category : error - Description : Join domain failure - FullFormat : Join domain failed. - vCenter : vCenter01 - - EventType : ExtendedEvent - EventTypeId : ad.event.LeaveDomainFailedEvent - Category : error - Description : Leave domain failure - FullFormat : Leave domain failed. - vCenter : vCenter01 - ..... -#> - [CmdletBinding()] - param ( - [VMware.Vim.EventCategory]$Category - ) - - foreach ($Mgr in (Get-View EventManager)) { - $vCenter = $Mgr.Client.ServiceUrl.Split('/')[2] - if ($PSBoundParameters.ContainsKey('Category')) { - $Events += $Mgr.Description.EventInfo | Where-Object -FilterScript { - $_.Category -eq $PSBoundParameters['Category'] - } - } else { - $Events += $Mgr.Description.EventInfo - } - - $Events | ForEach-Object -Process { - $Hash = [ordered]@{} - $Hash.Add('EventType', $_.Key) - if ($_.Key -eq 'ExtendedEvent' -or $_.Key -eq 'EventEx') { - $Hash.Add('EventTypeId', $_.FullFormat.Split('|')[0]) - } - $Hash.Add('Category', $_.Category) - $Hash.Add('Description', $_.Description) - if ($Hash['EventType'] -eq 'ExtendedEvent' -or $Hash['EventType'] -eq 'EventEx') { - $Hash.Add('FullFormat', $_.FullFormat.Split('|')[1]) - } else { - $Hash.Add('FullFormat', $_.FullFormat) - } - $Hash.Add('vCenter', $vCenter) - New-Object -TypeName System.Management.Automation.PSObject -Property $Hash - } - } -} #End of Get-EventId function \ No newline at end of file From 6365ed0bd179574bf9e8f43ceeecb1fec66040a0 Mon Sep 17 00:00:00 2001 From: jrob24 Date: Thu, 21 Sep 2017 23:32:58 -0500 Subject: [PATCH 03/29] Delete New-vCenterAlarms.ps1 --- Modules/vCenter.Alarms/New-vCenterAlarms.ps1 | 79 -------------------- 1 file changed, 79 deletions(-) delete mode 100644 Modules/vCenter.Alarms/New-vCenterAlarms.ps1 diff --git a/Modules/vCenter.Alarms/New-vCenterAlarms.ps1 b/Modules/vCenter.Alarms/New-vCenterAlarms.ps1 deleted file mode 100644 index e3ba5c8..0000000 --- a/Modules/vCenter.Alarms/New-vCenterAlarms.ps1 +++ /dev/null @@ -1,79 +0,0 @@ -<# - - =========================================================================== - Created by: Jason Robinson - Created on: 05/2017 - Twitter: @jrob24 - Filename: New-vCenterAlarms.ps1 - =========================================================================== - .DESCRIPTION - Examples of creating alarms using vCenter.Alarm module -#> - -Import-Module -Name vCenter.Alarms - -Write-Verbose -Message "Example 1 : Creating new Host CPU Usage alarm (Metric based alarm)" -Write-Verbose -Message "Finding the metric id for 'cpu.usage.average'" -$MetricId = (Get-MetricId -MetricGroup CPU | Where-Object -FilterScript { $_.Name -eq 'cpu.usage.average' }).Key -Write-Verbose -Message "Creating an alarm trigger for cpu.usage.average of 90% for 15mins (Warning) & 95% for 10mins (Alert) on the HostSystem object type" -$Trigger = New-AlarmTrigger -MetricId $MetricId -MetricOperator isAbove -ObjectType HostSystem -Yellow 90 -YellowInterval 15 -Red 95 -RedInterval 10 -Write-Verbose -Message "Creates a new alarm called 'Host CPU Usage' at the root level of vCenter" -New-AlarmDefinition -Name "Host CPU Usage" -Description "Alarm on 95%" -Entity Datacenters -Trigger $Trigger -ActionRepeatMinutes 10 -Write-Verbose -Message "Configures the alarm to send snmp traps" -Get-AlarmDefinition -Name "Host CPU Usage" | vSphere.Alarms\New-AlarmAction -Snmp -GreenToYellow Once -YellowToRed Repeat - -Write-Verbose -Message "Example 2 : Creating new HA Disabled alarm (Event based alarm)" -Write-Verbose -Message "Finding the event type for 'HA disabled for cluster'" -$EventType = (Get-EventId | Where-Object -FilterScript { $_.Description -match 'HA disabled for cluster' }).EventType -Write-Verbose -Message "Creating an alarm trigger for 'DasDisabledEvent' on the ClusterComputeResource object type" -$Trigger = New-AlarmTrigger -EventType $EventType -Status Red -ObjectType ClusterComputeResource -Write-Verbose -Message "Creates a new alarm called 'HA Disabled' at the root level of vCenter" -New-AlarmDefinition -Name "HA Disabled" -Description "Alarm on HA" -Entity Datacenters -Trigger $Trigger -ActionRepeatMinutes 30 -Write-Verbose -Message "Configures the alarm to send an email every 30mins" -$EmailParams = @{ - Email = $true - To = 'helpdesk@company.com' - Subject = 'HA Disabled' -} -Get-AlarmDefinition -Name "HA Disabled" | vCenter.Alarms\New-AlarmAction @EmailParams -YellowToRed Repeat - -Write-Verbose -Message "Example 3 : Creating new Host Connection State alarm (State based alarm)" -Write-Verbose -Message "Creating an alarm trigger for StateType of 'runtime.connectionState' on the HostSystem object type" -$Trigger = New-AlarmTrigger -StateType runtime.connectionState -StateOperator isEqual -YellowStateCondition disconnected -RedStateCondition notResponding -ObjectType HostSystem -Write-Verbose -Message "Creates a new alarm called 'Host Connection State' at the root level of vCenter" -New-AlarmDefinition -Name "Host Connection State" -Description "Connection State" -Entity Datacenters -Trigger $Trigger -Write-Verbose -Message "Configures the alarm to send an email once" -$EmailParams = @{ - Email = $true - To = 'helpdesk@company.com' - Subject = 'Host Connection Lost' -} -Get-AlarmDefinition -Name "Host Connection State" | vCenter.Alarms\New-AlarmAction @EmailParams -YellowToRed Once - -Write-Verbose -Message "Example 4 : Creating new Lost Storage Connectivity (Event based alarm)" -Write-Verbose -Message "Find the event type for 'Lost Storage Connectivity'" -Get-EventId | Where-Object -FilterScript { $_.Description -match 'Lost Storage Connectivity' } -Write-Verbose -Message "Two results returned, we want esx not vprob" - <# - EventType : EventEx - EventTypeId : esx.problem.storage.connectivity.lost - Category : error - Description : Lost Storage Connectivity - FullFormat : Lost connectivity to storage device { 1 }. Path { 2 } is down. Affected datastores: { 3 }. - vCenter : vCenter01 - - EventType : EventEx - EventTypeId : vprob.storage.connectivity.lost - Category : error - Description : Lost Storage Connectivity - FullFormat : Lost connectivity to storage device { 1 }. Path { 2 } is down. Affected datastores: { 3 }. - vCenter : vCenter01 - #> -Write-Verbose -Message "Since the event type is EventEx, we need both the EventType & EventTypeId to create the trigger" -$EventType = Get-EventId | Where-Object -FilterScript { $_.EventTypeId -eq 'esx.problem.storage.connectivity.lost' } -Write-Verbose -Message "Creating an alarm trigger for 'DasDisabledEvent' on the ClusterComputeResource object type" -$Trigger = New-AlarmTrigger -EventType $EventType.EventType -EventTypeId $EventType.EventTypeId -Status Red -ObjectType HostSystem -Write-Verbose -Message "Creates a new alarm called 'Lost Storage Connectivity' at the root level of vCenter" -New-AlarmDefinition -Name "Lost Storage Connectivity" -Description "Lost Storage" -Entity Datacenters -Trigger $Trigger -ActionRepeatMinutes 5 -Write-Verbose -Message "Configures the alarm to send an snmp every 5mins" -Get-AlarmDefinition -Name "Lost Storage Connectivity" | vCenter.Alarms\New-AlarmAction -Snmp -YellowToRed Repeat \ No newline at end of file From 76556f26c2699f8b2f98944e14bed05854e2dbe9 Mon Sep 17 00:00:00 2001 From: jrob24 Date: Thu, 21 Sep 2017 23:33:30 -0500 Subject: [PATCH 04/29] Initial commit --- Modules/vCenter.Alarms/New-vCenterAlarms.ps1 | 79 ++ Modules/vCenter.Alarms/vCenter.Alarms.psm1 | 736 +++++++++++++++++++ 2 files changed, 815 insertions(+) create mode 100644 Modules/vCenter.Alarms/New-vCenterAlarms.ps1 create mode 100644 Modules/vCenter.Alarms/vCenter.Alarms.psm1 diff --git a/Modules/vCenter.Alarms/New-vCenterAlarms.ps1 b/Modules/vCenter.Alarms/New-vCenterAlarms.ps1 new file mode 100644 index 0000000..e3ba5c8 --- /dev/null +++ b/Modules/vCenter.Alarms/New-vCenterAlarms.ps1 @@ -0,0 +1,79 @@ +<# + + =========================================================================== + Created by: Jason Robinson + Created on: 05/2017 + Twitter: @jrob24 + Filename: New-vCenterAlarms.ps1 + =========================================================================== + .DESCRIPTION + Examples of creating alarms using vCenter.Alarm module +#> + +Import-Module -Name vCenter.Alarms + +Write-Verbose -Message "Example 1 : Creating new Host CPU Usage alarm (Metric based alarm)" +Write-Verbose -Message "Finding the metric id for 'cpu.usage.average'" +$MetricId = (Get-MetricId -MetricGroup CPU | Where-Object -FilterScript { $_.Name -eq 'cpu.usage.average' }).Key +Write-Verbose -Message "Creating an alarm trigger for cpu.usage.average of 90% for 15mins (Warning) & 95% for 10mins (Alert) on the HostSystem object type" +$Trigger = New-AlarmTrigger -MetricId $MetricId -MetricOperator isAbove -ObjectType HostSystem -Yellow 90 -YellowInterval 15 -Red 95 -RedInterval 10 +Write-Verbose -Message "Creates a new alarm called 'Host CPU Usage' at the root level of vCenter" +New-AlarmDefinition -Name "Host CPU Usage" -Description "Alarm on 95%" -Entity Datacenters -Trigger $Trigger -ActionRepeatMinutes 10 +Write-Verbose -Message "Configures the alarm to send snmp traps" +Get-AlarmDefinition -Name "Host CPU Usage" | vSphere.Alarms\New-AlarmAction -Snmp -GreenToYellow Once -YellowToRed Repeat + +Write-Verbose -Message "Example 2 : Creating new HA Disabled alarm (Event based alarm)" +Write-Verbose -Message "Finding the event type for 'HA disabled for cluster'" +$EventType = (Get-EventId | Where-Object -FilterScript { $_.Description -match 'HA disabled for cluster' }).EventType +Write-Verbose -Message "Creating an alarm trigger for 'DasDisabledEvent' on the ClusterComputeResource object type" +$Trigger = New-AlarmTrigger -EventType $EventType -Status Red -ObjectType ClusterComputeResource +Write-Verbose -Message "Creates a new alarm called 'HA Disabled' at the root level of vCenter" +New-AlarmDefinition -Name "HA Disabled" -Description "Alarm on HA" -Entity Datacenters -Trigger $Trigger -ActionRepeatMinutes 30 +Write-Verbose -Message "Configures the alarm to send an email every 30mins" +$EmailParams = @{ + Email = $true + To = 'helpdesk@company.com' + Subject = 'HA Disabled' +} +Get-AlarmDefinition -Name "HA Disabled" | vCenter.Alarms\New-AlarmAction @EmailParams -YellowToRed Repeat + +Write-Verbose -Message "Example 3 : Creating new Host Connection State alarm (State based alarm)" +Write-Verbose -Message "Creating an alarm trigger for StateType of 'runtime.connectionState' on the HostSystem object type" +$Trigger = New-AlarmTrigger -StateType runtime.connectionState -StateOperator isEqual -YellowStateCondition disconnected -RedStateCondition notResponding -ObjectType HostSystem +Write-Verbose -Message "Creates a new alarm called 'Host Connection State' at the root level of vCenter" +New-AlarmDefinition -Name "Host Connection State" -Description "Connection State" -Entity Datacenters -Trigger $Trigger +Write-Verbose -Message "Configures the alarm to send an email once" +$EmailParams = @{ + Email = $true + To = 'helpdesk@company.com' + Subject = 'Host Connection Lost' +} +Get-AlarmDefinition -Name "Host Connection State" | vCenter.Alarms\New-AlarmAction @EmailParams -YellowToRed Once + +Write-Verbose -Message "Example 4 : Creating new Lost Storage Connectivity (Event based alarm)" +Write-Verbose -Message "Find the event type for 'Lost Storage Connectivity'" +Get-EventId | Where-Object -FilterScript { $_.Description -match 'Lost Storage Connectivity' } +Write-Verbose -Message "Two results returned, we want esx not vprob" + <# + EventType : EventEx + EventTypeId : esx.problem.storage.connectivity.lost + Category : error + Description : Lost Storage Connectivity + FullFormat : Lost connectivity to storage device { 1 }. Path { 2 } is down. Affected datastores: { 3 }. + vCenter : vCenter01 + + EventType : EventEx + EventTypeId : vprob.storage.connectivity.lost + Category : error + Description : Lost Storage Connectivity + FullFormat : Lost connectivity to storage device { 1 }. Path { 2 } is down. Affected datastores: { 3 }. + vCenter : vCenter01 + #> +Write-Verbose -Message "Since the event type is EventEx, we need both the EventType & EventTypeId to create the trigger" +$EventType = Get-EventId | Where-Object -FilterScript { $_.EventTypeId -eq 'esx.problem.storage.connectivity.lost' } +Write-Verbose -Message "Creating an alarm trigger for 'DasDisabledEvent' on the ClusterComputeResource object type" +$Trigger = New-AlarmTrigger -EventType $EventType.EventType -EventTypeId $EventType.EventTypeId -Status Red -ObjectType HostSystem +Write-Verbose -Message "Creates a new alarm called 'Lost Storage Connectivity' at the root level of vCenter" +New-AlarmDefinition -Name "Lost Storage Connectivity" -Description "Lost Storage" -Entity Datacenters -Trigger $Trigger -ActionRepeatMinutes 5 +Write-Verbose -Message "Configures the alarm to send an snmp every 5mins" +Get-AlarmDefinition -Name "Lost Storage Connectivity" | vCenter.Alarms\New-AlarmAction -Snmp -YellowToRed Repeat \ No newline at end of file diff --git a/Modules/vCenter.Alarms/vCenter.Alarms.psm1 b/Modules/vCenter.Alarms/vCenter.Alarms.psm1 new file mode 100644 index 0000000..5f13f3f --- /dev/null +++ b/Modules/vCenter.Alarms/vCenter.Alarms.psm1 @@ -0,0 +1,736 @@ +<# + =========================================================================== + Created by: Jason Robinson + Created on: 05/2017 + Twitter: @jrob24 + =========================================================================== + .DESCRIPTION + PowerShell Module to help with creation of vCenter Alarms + .NOTES + See New-vCenterAlarms.ps1 for examples of alarm creation + + * Tested against PowerShell 5.0 + * Tested against PowerCLI 6.5.1 build 5377412 + * Tested against vCenter 6.0 + * Tested against ESXi 5.5/6.0 +#> + +function New-AlarmDefinition { +<# + .SYNOPSIS + This cmdlet creates a new alarm defintion on the specified entity in vCenter. + .DESCRIPTION + This cmdlet creates a new alarm defintion on the specified entity in vCenter. + An alarm trigger is required in order to create a new alarm definition. + They can be created by using the New-AlarmTrigger cmdlet. + + After the alarm definition is created, if alarm actions are required use + the cmdlet New-AlarmAction to create actions for the alarm. + .PARAMETER Name + Specifies the name of the alarm you want to create. + .PARAMETER Description + Specifies the description for the alarm. + .PARAMETER Entity + Specifies where to create the alarm. To create the alarm at the root + level of vCenter use the entity 'Datacenters', otherwise specify any + object name. + .PARAMETER Trigger + Specifies the alarm event, state, or metric trigger(s). The alarm + trigger(s) are created with the New-AlarmTrigger cmdlet. For more + information about triggers, run Get-Help New-AlarmTrigger. + .PARAMETER Enabled + Specifies if the alarm is enabled when it is created. If unset, the + default value is true. + .PARAMETER ActionRepeatMinutes + Specifies the frequency how often the actions should repeat when an alarm + does not change state. + .PARAMETER ReportingFrequency + Specifies how often the alarm is triggered, measured in minutes. A zero + value means the alarm is allowed to trigger as often as possible. A + nonzero value means that any subsequent triggers are suppressed for a + period of minutes following a reported trigger. + + If unset, the default value is 0. Allowed range is 0 - 60. + .PARAMETER ToleranceRange + Specifies the tolerance range for the metric triggers, measure in + percentage. A zero value means that the alarm triggers whenever the metric + value is above or below the specified value. A nonzero means that the + alarm triggers only after reaching a certain percentage above or below + the nominal trigger value. + + If unset, the default value is 0. Allowed range is 0 - 100. + .PARAMETER Server + Specifies the vCenter Server system on which you want to run the cmdlet. + If no value is passed to this parameter, the command runs on the default + server, $DefaultVIServer. For more information about default servers, + see the description of Connect-VIServer. + .OUTPUTS + VMware.Vim.ManagedObjectReference + .NOTES + This cmdlet requires a connection to vCenter to create the alarm action. + .LINKS + http://pubs.vmware.com/vsphere-6-0/topic/com.vmware.wssdk.apiref.doc/vim.alarm.AlarmSpec.html + .EXAMPLE + PS C:\> $trigger = New-AlarmTrigger -StateType runtime.connectionState -StateOperator isEqual -YellowStateCondition disconnected -RedStateCondition notResponding -ObjectType HostSystem + PS C:\> New-AlarmDefinition -Name 'Host Connection' -Description 'Host Connection State Alarm -Entity Datacenters -Trigger $trigger -ActionRepeatMinutes 10 + + Type Value + ---- ----- + Alarm alarm-1801 + + This will create a host connection state alarm trigger and store it in + the variable $trigger. Then it will create a new alarm 'Host Connection' + on the root level of vCenter and set the action to repeat every 10 mins. +#> + [CmdletBinding(SupportsShouldProcess = $true, ConfirmImpact = 'High')] + param ( + [Parameter(Mandatory = $true)] + [ValidateNotNullOrEmpty()] + [Alias('AlarmName')] + [string]$Name, + + [string]$Description, + + [Parameter(Mandatory = $true)] + [string]$Entity, + + [Parameter(Mandatory = $true)] + [ValidateNotNullOrEmpty()] + [VMware.Vim.AlarmExpression[]]$Trigger, + + [boolean]$Enabled = $true, + + [ValidateRange(0, 60)] + [int32]$ActionRepeatMinutes, + + [ValidateRange(0, 60)] + [int32]$ReportingFrequency = 0, + + [ValidateRange(0, 100)] + [int32]$ToleranceRange = 0, + + [string]$Server + ) + BEGIN { + Write-Verbose -Message "Adding parameters with default values to PSBoundParameters" + foreach ($Key in $MyInvocation.MyCommand.Parameters.Keys) { + $Value = Get-Variable $Key -ValueOnly -ErrorAction SilentlyContinue + if ($Value -and !$PSBoundParameters.ContainsKey($Key)) { + $PSBoundParameters[$Key] = $Value + } + } + } + PROCESS { + try { + if ($PSBoundParameters.ContainsKey('Server')) { + $Object = Get-Inventory -Name $PSBoundParameters['Entity'] -ErrorAction Stop -Server $PSBoundParameters['Server'] + $AlarmMgr = Get-View AlarmManager -ErrorAction Stop -Server $PSBoundParameters['Server'] + } else { + $Object = Get-Inventory -Name $PSBoundParameters['Entity'] -ErrorAction Stop -Server $global:DefaultVIServer + $AlarmMgr = Get-View AlarmManager -ErrorAction Stop -Server $global:DefaultVIServer + } + + if ($PSCmdlet.ShouldProcess($global:DefaultVIServer, "Create alarm $($PSBoundParameters['Name'])")) { + $Alarm = New-Object -TypeName VMware.Vim.AlarmSpec + $Alarm.Name = $PSBoundParameters['Name'] + $Alarm.Description = $PSBoundParameters['Description'] + $Alarm.Enabled = $PSBoundParameters['Enabled'] + $Alarm.Expression = New-Object -TypeName VMware.Vim.OrAlarmExpression + $Alarm.Expression.Expression += $PSBoundParameters['Trigger'] + $Alarm.Setting = New-Object -TypeName VMware.Vim.AlarmSetting + $Alarm.Setting.ReportingFrequency = $PSBoundParameters['ReportingFrequency'] * 60 + $Alarm.Setting.ToleranceRange = $PSBoundParameters['ToleranceRange'] * 100 + $Alarm.ActionFrequency = $PSBoundParameters['ActionRepeatMinutes'] * 60 + $AlarmMgr.CreateAlarm($Object.Id, $Alarm) + } + } catch { + $PSCmdlet.ThrowTerminatingError($_) + } + } +} #End of New-AlarmDefinition function + +function New-AlarmAction { +<# + .SYNOPSIS + This cmdlet creates an alarm action on the specified alarm definition. + .DESCRIPTION + This cmdlet creates an alarm action on the specified alarm definition. + This cmdlet differs from the VMware PowerCLI New-AlarmAction cmdlet as it + will create the transitions of the alarm state. It requires an alarm + action and at least one transition to be specified. + + The transition indicates when the action executes and if it repeats. + There are only four acceptable transitions: green to yellow, yellow to + red, red to yellow, and yellow to green. At least one pair must be + specified or the results will be an invalid. + + If an alarm action already exists on the alarm definition, it will be + overwritten if the same alarm action is specified. For example if the + alarm definition already has an alarm action of Snmp on the transition + of green to yellow and the cmdlet is used to create a new action of + Snmp on the transition of yellow to red, it will overwrite the existing + action and transition. The end result will be one Snmp action on the + transition of yellow to red. If you want the old to transition to remain + both should be specified during the usage of the cmdlet. + .PARAMETER AlarmDefinition + Specifies the alarm definition for which you want to configure actions. + The alarm definition can be retreived by using the Get-AlarmDefinition + cmdlet. + .PARAMETER Snmp + Indicates that a SNMP message is sent when the alarm is activated. + .PARAMETER Email + Indicates that when the alarm is activated, the system sends an email + message to the specified address. Use the Subject, To, CC, and Body + parameters to customize the alarm message. + .PARAMETER To + Specifies the email address to which you want to send a message. + .PARAMETER Cc + Specifies the email address you want to add to the CC field of the email + message. + .PARAMETER Subject + Specifies a subject for the email address message you want to send. + .PARAMETER Body + Specifies the text of the email message. + .PARAMETER GreenToYellow + Specifies the alarm action for the green to yellow transition. Allowed + values are 'Once' and 'Repeat'. If parameter is not set transition will + remain unset. + .PARAMETER YellowToRed + Specifies the alarm action for the yellow to red transition. Allowed + values are 'Once' and 'Repeat'. If parameter is not set transition will + remain unset. + .PARAMETER RedToYellow + Specifies the alarm action for the red to yellow transition. Allowed + values are 'Once' and 'Repeat'. If parameter is not set transition will + remain unset. + .PARAMETER YellowToGreen + Specifies the alarm action for the yellow to green transition. Allowed + values are 'Once' and 'Repeat'. If parameter is not set transition will + remain unset. + .NOTES + This cmdlet requires a connection to vCenter to create the alarm action. + + When using this cmdlet specify the Module-Qualified cmdlet name to avoid + using the New-AlarmAction cmdlet with VMware PowerCLI. + .EXAMPLE + PS C:\> vCenter.Alarms\New-AlarmAction -AlarmDefinition (Get-AlarmDefintion "Host CPU Usage") -Snmp -YellowToRed Repeat + + This will create an Snmp alarm action on the "Host CPU Usage" alarm + transition of yellow to red. The alarm action will also repeat, as per + the action frequency defined on the alarm. + .EXAMPLE + PS C:\> Get-AlarmDefintion "Cluster HA Status" | vCenter.Alarms\New-AlarmAction -Email -To helpdesk@company.com -GreenToYellow Once -YellowToRed Once + + This will create an Email alarm action on the "Cluster HA Status" alarm + transition of green to yellow and yellow to red. The alarm action will + send an email to helpdesk@company.com one time per transition. +#> + [CmdletBinding(SupportsShouldProcess = $true, ConfirmImpact = 'Low')] + param ( + [Parameter(Mandatory = $true, ValueFromPipeline = $true)] + [VMware.VimAutomation.ViCore.Types.V1.Alarm.AlarmDefinition]$AlarmDefinition, + + [Parameter(Mandatory = $true, ParameterSetName = 'Snmp')] + [switch]$Snmp, + + [Parameter(Mandatory = $true, ParameterSetName = 'Email')] + [switch]$Email, + + [Parameter(Mandatory = $true, ParameterSetName = 'Email')] + [string[]]$To, + + [Parameter(ParameterSetName = 'Email')] + [string[]]$Cc, + + [Parameter(ParameterSetName = 'Email')] + [string]$Subject, + + [Parameter(ParameterSetName = 'Email')] + [string]$Body, + + [ValidateSet('Once', 'Repeat')] + [string]$GreenToYellow, + + [ValidateSet('Once', 'Repeat')] + [string]$YellowToRed, + + [ValidateSet('Once', 'Repeat')] + [string]$RedToYellow, + + [ValidateSet('Once', 'Repeat')] + [string]$YellowToGreen + ) + + BEGIN { + } + PROCESS { + try { + $AlarmView = Get-View -Id $PSBoundParameters['AlarmDefinition'].Id -Server ($PSBoundParameters['AlarmDefinition'].Uid.Split('@:')[1]) + $Alarm = New-Object -TypeName VMware.Vim.AlarmSpec + $Alarm.Name = $AlarmView.Info.Name + $Alarm.Description = $AlarmView.Info.Description + $Alarm.Enabled = $AlarmView.Info.Enabled + $Alarm.ActionFrequency = $AlarmView.Info.ActionFrequency + $Alarm.Action = New-Object VMware.Vim.GroupAlarmAction + $Trigger = New-Object VMware.Vim.AlarmTriggeringAction + + Write-Verbose -Message "Defining alarm actions" + if ($PSCmdlet.ParameterSetName -eq 'Snmp') { + $Trigger.Action = New-Object -TypeName VMware.Vim.SendSNMPAction + } elseif ($PSCmdlet.ParameterSetName -eq 'Email') { + $Trigger.Action = New-Object -TypeName VMware.Vim.SendEmailAction + $Trigger.Action.ToList = $PSBoundParameters['To'].GetEnumerator() | ForEach-Object -Process { + "$_;" + } + if ($PSBoundParameters.ContainsKey('Cc')) { + $Trigger.Action.CcList = $PSBoundParameters['Cc'].GetEnumerator() | ForEach-Object -Process { + "$_;" + } + } else { + $Trigger.Action.CcList = $null + } + $Trigger.Action.Subject = $PSBoundParameters['Subject'] + $Trigger.Action.Body = $PSBoundParameters['Body'] + } + + Write-Verbose -Message "Defining alarm transitions" + if ($PSBoundParameters.ContainsKey('GreenToYellow')) { + $Trans1 = New-Object -TypeName VMware.Vim.AlarmTriggeringActionTransitionSpec + $Trans1.StartState = 'green' + $Trans1.FinalState = 'yellow' + if ($PSBoundParameters['GreenToYellow'] -eq 'Repeat') { + $Trans1.Repeats = $true + } + $Trigger.TransitionSpecs += $Trans1 + } + + if ($PSBoundParameters.ContainsKey('YellowToRed')) { + $Trans2 = New-Object -TypeName VMware.Vim.AlarmTriggeringActionTransitionSpec + $Trans2.StartState = 'yellow' + $Trans2.FinalState = 'red' + if ($PSBoundParameters['YellowToRed'] -eq 'Repeat') { + $Trans2.Repeats = $true + } else { + $Trans2.Repeats = $false + } + $Trigger.TransitionSpecs += $Trans2 + } + + if ($PSBoundParameters.ContainsKey('RedToYellow')) { + $Trans3 = New-Object -TypeName VMware.Vim.AlarmTriggeringActionTransitionSpec + $Trans3.StartState = 'red' + $Trans3.FinalState = 'yellow' + if ($PSBoundParameters['RedToYellow'] -eq 'Repeat') { + $Trans3.Repeats = $true + } else { + $Trans3.Repeats = $false + } + $Trigger.TransitionSpecs += $Trans3 + } + + if ($PSBoundParameters.ContainsKey('YellowToGreen')) { + $Trans4 = New-Object -TypeName VMware.Vim.AlarmTriggeringActionTransitionSpec + $Trans4.StartState = 'yellow' + $Trans4.FinalState = 'green' + if ($PSBoundParameters['YellowToGreen'] -eq 'Repeat') { + $Trans4.Repeats = $true + } else { + $Trans4.Repeats = $false + } + $Trigger.TransitionSpecs += $Trans4 + } + + $Alarm.Action.Action += $Trigger + $Alarm.Expression = New-Object -TypeName VMware.Vim.OrAlarmExpression + $Alarm.Expression.Expression += $AlarmView.Info.Expression.Expression + $Alarm.Setting += $AlarmView.Info.Setting + $AlarmView.ReconfigureAlarm($Alarm) + } catch { + $PSCmdlet.ThrowTerminatingError($_) + } + } +} #End of New-AlarmAction function + +function New-AlarmTrigger { +<# + .SYNOPSIS + This cmdlet creates a vCenter event, state, or metric alarm trigger. + .DESCRIPTION + This cmdlet creates a vCenter event, state, or metric alarm trigger. + The trigger is used with the New-AlarmDefinition cmdlet to create a new + alarm in vCenter. This cmdlet will only create one alarm trigger. If more + triggers are required store the triggers in an array. + .PARAMETER EventType + Specifies the type of the event to trigger on. The event types can be + discovered by using the Get-EventId cmdlet. If the the event type is + 'EventEx' or 'ExtendedEvent' the EventTypeId parameter is required. + .PARAMETER EventTypeId + Specifies the id of the event type. Only used when the event type is an + 'EventEx' or 'ExtendedEvent'. + .PARAMETER Status + Specifies the status of the event. Allowed values are green, yellow, or + red. + .PARAMETER StateType + Specifies the state type to trigger on. Allowed values are + runtime.powerstate (HostSystem), summary.quickStats.guestHeartbeatStatus + (VirtualMachine), or runtime.connectionState (VirtualMachine). + .PARAMETER StateOperator + Specifies the operator condition on the target state. Allowed values are + 'isEqual' or 'isUnequal'. + .PARAMETER YellowStateCondition + Specifies the yellow state condition. When creating a state alarm + trigger at least one condition must be specified for a valid trigger to + be created. If the parameter is not set, the yellow condition is unset. + .PARAMETER RedStateCondition + Specifies the red state condition. When creating a state alarm trigger + at least one condition must be specified for a valid trigger to be + created. If the parameter is not set, the red condition is unset. + .PARAMETER MetricId + Specifies the id of the metric to trigger on. The metric ids can be + discovered by using the Get-MetricId cmdlet. + .PARAMETER MetricOperator + Specifies the operator condition on the target metric. Allowed values + are 'isAbove' or 'isBelow'. + .PARAMETER Yellow + Specifies the threshold value that triggers a yellow status. Allowed + range is 1% - 100%. + .PARAMETER YellowInterval + Specifies the time interval in minutes for which the yellow condition + must be true before the yellow status is triggered. If unset, the yellow + status is triggered immediately when the yellow condition becomes true. + .PARAMETER Red + Specifies the threshold value that triggers a red status. Allowed range + is 1% - 100%. + .PARAMETER RedInterval + Specifies the time interval in minutes for which the red condition must + be true before the red status is triggered. If unset, the red status is + triggered immediately when the red condition becomes true. + .PARAMETER ObjectType + Specifies the type of object on which the event is logged, the object + type containing the state condition or the type of object containing the + metric. + + When creating a state alarm trigger the only acceptable values are + 'HostSystem' or 'VirtualMachine'. The supported state types for each object + are as follows: + VirtualMachine type: runtime.powerState or summary.quickStats.guestHeartbeatStatus + HostSystem type: runtime.connectionState + .OUTPUTS + (Event|State|Metric)AlarmExpression + .NOTES + This cmdlet requires the PowerCLI module to be imported. + .LINK + Event Alarm Trigger + http://pubs.vmware.com/vsphere-6-0/topic/com.vmware.wssdk.apiref.doc/vim.alarm.EventAlarmExpression.html + + State Alarm Trigger + http://pubs.vmware.com/vsphere-6-0/topic/com.vmware.wssdk.apiref.doc/vim.alarm.StateAlarmExpression.html + + Metric Alarm Trigger + http://pubs.vmware.com/vsphere-6-0/topic/com.vmware.wssdk.apiref.doc/vim.alarm.MetricAlarmExpression.html + .EXAMPLE + PS C:\> New-AlarmTrigger -EventType "DasDisabledEvent" -Status Red -ObjectType ClusterComputeResource + + Comparisons : + EventType : DasDisabledEvent + ObjectType : ClusterComputeResource + Status : red + + Creates an event trigger on 'DasDisabledEvent' (HA Disabled) with a + status on 'Red'. The object type is a ClusterComputerResource because + this event occurs at a cluster level. + .EXAMPLE + PS C:\> New-AlarmTrigger -MetricId (Get-MetricId | Where Name -EQ 'cpu.usage.average').Key -Operator isAbove -Yellow 90 -YellowInterval 30 -Red 98 -RedInterval 15 -ObjectType HostSytem + + Operator : isAbove + Type : HostSytem + Metric : VMware.Vim.PerfMetricId + Yellow : 9000 + YellowInterval : 30 + Red : 9800 + RedInterval : 15 + + Creates a trigger on the 'cpu.usage.average' metric where the warning + condition must be above 90% for 30mins and the alert condition must be + above 98% for 15mins. The object type is a HostSystem. + .EXAMPLE + PS C:\temp> New-AlarmTrigger -StateType runtime.connectionState -StateOperator isEqual -YellowStateCondition Disconnected -RedStateCondition notResponding -ObjectType HostSystem + + Operator : isEqual + Type : HostSystem + StatePath : runtime.connectionState + Yellow : Disconnected + Red : notResponding + + Creates a trigger on the 'runtime.connectionState' condition where the + warning condition is 'disconnected' and the alert condition is + 'notResponding'. The object type is a HostSystem. +#> + [CmdletBinding(SupportsShouldProcess = $true, ConfirmImpact = 'Low')] + param ( + [Parameter(Mandatory = $true, ParameterSetName = 'Event')] + [string]$EventType, + + [Parameter(ParameterSetName = 'Event')] + [string]$EventTypeId, + + [Parameter(Mandatory = $true, ParameterSetName = 'Event')] + [ValidateSet('Green', 'Yellow', 'Red')] + [string]$Status, + + [Parameter(Mandatory = $true, ParameterSetName = 'State')] + [ValidateSet('runtime.powerState', 'summary.quickStats.guestHeartbeatStatus', 'runtime.connectionState')] + [string]$StateType, + + [Parameter(Mandatory = $true, ParameterSetName = 'State')] + [VMware.Vim.StateAlarmOperator]$StateOperator, + + [Parameter(ParameterSetName = 'State')] + [ValidateSet('disconnected', 'notResponding', 'connected', 'noHeartbeat', 'intermittentHeartbeat', 'poweredOn', 'poweredOff', 'suspended')] + [string]$YellowStateCondition, + + [Parameter(ParameterSetName = 'State')] + [ValidateSet('disconnected', 'notResponding', 'connected', 'noHeartbeat', 'intermittentHeartbeat', 'poweredOn', 'poweredOff', 'suspended')] + [string]$RedStateCondition, + + [Parameter(Mandatory = $true, ParameterSetName = 'Metric')] + [string]$MetricId, + + [Parameter(Mandatory = $true, ParameterSetName = 'Metric')] + [VMware.Vim.MetricAlarmOperator]$MetricOperator, + + [Parameter(ParameterSetName = 'Metric')] + [ValidateRange(1, 100)] + [int32]$Yellow, + + [Parameter(ParameterSetName = 'Metric')] + [ValidateRange(1, 90)] + [int32]$YellowInterval, + + [Parameter(ParameterSetName = 'Metric')] + [ValidateRange(1, 100)] + [int32]$Red, + + [Parameter(ParameterSetName = 'Metric')] + [ValidateRange(1, 90)] + [int32]$RedInterval, + + [Parameter(Mandatory = $true)] + [ValidateSet('ClusterComputeResource', 'Datacenter', 'Datastore', 'DistributedVirtualSwitch', 'HostSystem', 'Network', 'ResourcePool', 'VirtualMachine')] + [string]$ObjectType + ) + try { + if ($PSCmdlet.ShouldProcess("vCenter alarm", "Create $($PSCmdlet.ParameterSetName) trigger")) { + if ($PSCmdlet.ParameterSetName -eq 'Event') { + $Expression = New-Object -TypeName VMware.Vim.EventAlarmExpression + $Expression.EventType = $PSBoundParameters['EventType'] + if ($PSBoundParameters.ContainsKey('EventTypeId')) { + $Expression.EventTypeId = $PSBoundParameters['EventTypeId'] + } + $Expression.ObjectType = $PSBoundParameters['ObjectType'] + $Expression.Status = $PSBoundParameters['Status'] + $Expression + } elseif ($PSCmdlet.ParameterSetName -eq 'Metric') { + $Expression = New-Object -TypeName VMware.Vim.MetricAlarmExpression + $Expression.Metric = New-Object -TypeName VMware.Vim.PerfMetricId + $Expression.Metric.CounterId = $PSBoundParameters['MetricId'] + $Expression.Metric.Instance = "" + $Expression.Operator = $PSBoundParameters['MetricOperator'] + $Expression.Red = ($PSBoundParameters['Red'] * 100) + $Expression.RedInterval = ($PSBoundParameters['RedInterval'] * 60) + $Expression.Yellow = ($PSBoundParameters['Yellow'] * 100) + $Expression.YellowInterval = ($PSBoundParameters['YellowInterval'] * 60) + $Expression.Type = $PSBoundParameters['ObjectType'] + $Expression + } elseif ($PSCmdlet.ParameterSetName -eq 'State') { + $Expression = New-Object -TypeName VMware.Vim.StateAlarmExpression + $Expression.Operator = $PSBoundParameters['StateOperator'] + $Expression.Type = $PSBoundParameters['ObjectType'] + $Expression.StatePath = $PSBoundParameters['StateType'] + + if ($PSBoundParameters.ContainsKey('RedStateCondition')) { + if ($PSBoundParameters['RedStateCondition'] -eq 'intermittentHeartbeat') { + $Expression.Red = 'yellow' + } elseif ($PSBoundParameters['RedStateCondition'] -eq 'noHeartbeat') { + $Expression.Red = 'red' + } else { + $Expression.Red = $PSBoundParameters['RedStateCondition'] + } + } + + if ($PSBoundParameters.ContainsKey('YellowStateCondition')) { + if ($PSBoundParameters['YellowStateCondition'] -eq 'intermittentHeartbeat') { + $Expression.Yellow = 'yellow' + } elseif ($PSBoundParameters['YellowStateCondition'] -eq 'noHeartbeat') { + $Expression.Yellow = 'red' + } else { + $Expression.Yellow = $PSBoundParameters['YellowStateCondition'] + } + } + $Expression + } + } + } catch { + $PSCmdlet.ThrowTerminatingError($_) + } +} #End of New-AlarmTrigger function + +function Get-MetricId { +<# + .SYNOPSIS + This cmdlet collects all of the available metrics from vCenter. + .DESCRIPTION + This cmdlet collects all of the available metrics from vCenter. It will + provide the metric name, key, stats level, and summary of the metric. + The information can be used to identify the available metrics on vCenter + as well as gathering the metric key needed for configuring an alarm. + + The metric keys are unique across vCenters. If you are connected to + more than one vCenter metrics from each vCenter will be generated. A + vCenter property is available to help determine the correct metric key + on a given vCenter. This is extrememly useful when trying to create + a metric based vCenter alarm. + .PARAMETER MetricGroup + Specifies the name of the metric group you would like to see. Allowed + values are 'CPU', 'Mem', 'Disk', 'Net', and 'Datastore'. + .OUTPUTS + System.Management.Automation.PSCustomObject + .NOTES + This cmdlet requires a connection to vCenter to collect metric data. + .EXAMPLE + PS C:\> Get-MetricId -MetricGroup Mem + + Name : mem.usage.none + Key : 23 + Level : 4 + Summary : Memory usage as percentage of total configured or available memory + vCenter : vCenter01 + + Name : mem.usage.average + Key : 24 + Level : 1 + Summary : Memory usage as percentage of total configured or available memory + vCenter : vCenter01 + + Name : mem.usage.minimum + Key : 25 + Level : 4 + Summary : Memory usage as percentage of total configured or available memory + vCenter : vCenter01 + ..... + + Collects all of the available memory metrics on the connected vCenter. +#> + [CmdletBinding()] + param ( + [ValidateSet('CPU', 'Mem', 'Disk', 'Net', 'Datastore')] + [string]$MetricGroup + ) + + foreach ($Mgr in (Get-View PerformanceManager-PerfMgr)) { + $vCenter = $Mgr.Client.ServiceUrl.Split('/')[2] + if ($PSBoundParameters.ContainsKey('MetricGroup')) { + $Metrics += $Mgr.PerfCounter | Where-Object -FilterScript { + $_.GroupInfo.Key -eq $PSBoundParameters['MetricGroup'] + } + } else { + $Metrics += $Mgr.PerfCounter + } + + $Metrics | ForEach-Object -Process { + [pscustomobject] @{ + Name = $_.GroupInfo.Key + "." + $_.NameInfo.key + "." + $_.RollupType + Key = $_.Key + Level = $_.Level + Summary = $_.NameInfo.Summary + vCenter = $vCenter + } + } + } +} #End of Get-MetricId function + +function Get-EventId { +<# + .SYNOPSIS + This cmdlet collects all of the available events from vCenter. + .DESCRIPTION + This cmdlet collects all of the available events from vCenter. It will + provide the event type, event type id (if applicable), category, + description, and summary of the event. The information can be used to + identify the available events on vCenter as well as gathering the event + type and event type id (if applicable) required for configuring an alarm. + + If the event type is 'EventEx' or 'ExtendedEvent' both the event type + and event type id will be required to create a new event based vCenter + alarm. + + The event types can be unique across vCenters. If you are connected to + more than one vCenter events from each vCenter will be generated. A + vCenter property is available to help determine the correct event type + on a given vCenter. This is extrememly useful when trying to create + a event based vCenter alarm. + .PARAMETER Category + Specifies the name of the event category you would like to see. Allowed + values are 'info', 'warning', 'error', and 'user'. + .OUTPUTS + System.Management.Automation.PSCustomObject + .NOTES + This cmdlet requires a connection to vCenter to collect event data. + .EXAMPLE + PS C:\> Get-EventId -Category Error + + EventType : ExtendedEvent + EventTypeId : ad.event.ImportCertFailedEvent + Category : error + Description : Import certificate failure + FullFormat : Import certificate failed. + vCenter : vCenter01 + + EventType : ExtendedEvent + EventTypeId : ad.event.JoinDomainFailedEvent + Category : error + Description : Join domain failure + FullFormat : Join domain failed. + vCenter : vCenter01 + + EventType : ExtendedEvent + EventTypeId : ad.event.LeaveDomainFailedEvent + Category : error + Description : Leave domain failure + FullFormat : Leave domain failed. + vCenter : vCenter01 + ..... +#> + [CmdletBinding()] + param ( + [VMware.Vim.EventCategory]$Category + ) + + foreach ($Mgr in (Get-View EventManager)) { + $vCenter = $Mgr.Client.ServiceUrl.Split('/')[2] + if ($PSBoundParameters.ContainsKey('Category')) { + $Events += $Mgr.Description.EventInfo | Where-Object -FilterScript { + $_.Category -eq $PSBoundParameters['Category'] + } + } else { + $Events += $Mgr.Description.EventInfo + } + + $Events | ForEach-Object -Process { + $Hash = [ordered]@{} + $Hash.Add('EventType', $_.Key) + if ($_.Key -eq 'ExtendedEvent' -or $_.Key -eq 'EventEx') { + $Hash.Add('EventTypeId', $_.FullFormat.Split('|')[0]) + } + $Hash.Add('Category', $_.Category) + $Hash.Add('Description', $_.Description) + if ($Hash['EventType'] -eq 'ExtendedEvent' -or $Hash['EventType'] -eq 'EventEx') { + $Hash.Add('FullFormat', $_.FullFormat.Split('|')[1]) + } else { + $Hash.Add('FullFormat', $_.FullFormat) + } + $Hash.Add('vCenter', $vCenter) + New-Object -TypeName System.Management.Automation.PSObject -Property $Hash + } + } +} #End of Get-EventId function \ No newline at end of file From accbd83effe97f1a20c2ed2a1412e325947c9335 Mon Sep 17 00:00:00 2001 From: Kyle Ruddy Date: Sat, 14 Oct 2017 15:36:06 -0400 Subject: [PATCH 05/29] Clean Up Moving script resources to the scripting folder. --- get-peakvms.ps1 => Scripts/get-peakvms.ps1 | 0 get-ping.ps1 => Scripts/get-ping.ps1 | 0 2 files changed, 0 insertions(+), 0 deletions(-) rename get-peakvms.ps1 => Scripts/get-peakvms.ps1 (100%) rename get-ping.ps1 => Scripts/get-ping.ps1 (100%) diff --git a/get-peakvms.ps1 b/Scripts/get-peakvms.ps1 similarity index 100% rename from get-peakvms.ps1 rename to Scripts/get-peakvms.ps1 diff --git a/get-ping.ps1 b/Scripts/get-ping.ps1 similarity index 100% rename from get-ping.ps1 rename to Scripts/get-ping.ps1 From 795bcccad815dc26ec2a53c7d3d756e5d6616540 Mon Sep 17 00:00:00 2001 From: Kyle Ruddy Date: Sat, 14 Oct 2017 15:36:58 -0400 Subject: [PATCH 06/29] Get-VMNetworkPortId This script can be used to find the network Port-ID on the lost host. --- Scripts/Get-VMNetworkPortId.ps1 | 56 +++++++++++++++++++++++++++++++++ 1 file changed, 56 insertions(+) create mode 100644 Scripts/Get-VMNetworkPortId.ps1 diff --git a/Scripts/Get-VMNetworkPortId.ps1 b/Scripts/Get-VMNetworkPortId.ps1 new file mode 100644 index 0000000..ed130a6 --- /dev/null +++ b/Scripts/Get-VMNetworkPortId.ps1 @@ -0,0 +1,56 @@ +<# +.SYNOPSIS + Finds the local ESXi network Port-ID where a VM is assigned +.DESCRIPTION + Reports back a VM's Port-ID according to the local ESXi host. This correlates to the Port-ID which is displayed via ESXTop +.NOTES + Author: Kyle Ruddy, @kmruddy, thatcouldbeaproblem.com +.PARAMETER vm + The name of the desired VM +.EXAMPLE + PS> .\Get-VMNetworkPortId.ps1 -vm vmname +.EXAMPLE + PS> Get-VM -Name vmname | .\Get-VMNetworkPortId.ps1 +#> +[CmdletBinding(SupportsShouldProcess=$True)] + param( + [Parameter(Mandatory=$true,Position=0,ValueFromPipelineByPropertyName=$true)] + [Alias('Name')] + [String[]]$vm + ) + + Begin { + #Create an array to store output prior to return + $output = @() + + } + + Process { + #Loop through each of the input values + foreach ($v in $vm) { + #Validate the input is a valid VM + $vmobj = Get-VM -Name $v -erroraction silentlycontinue + if (!$vmobj) {Write-Verbose "No VM found by the name $vm."} + else { + #Create a temporary object to store individual ouput + $tempout = "" | select VM,PortId + #Start an ESXCLI session with the host where the VM resides + $esxcli = Get-EsxCli -VMHost $vmobj.VMHost -v2 + #ESXCLI call to obtain information about the VM, specifically its WorldID + $vmNetInfo = $esxcli.network.vm.list.Invoke() | ?{$_.Name -eq $vmobj.Name} + #Create spec to poll the host for the network information of the VM + $portArgs = $esxcli.network.vm.port.list.CreateArgs() + $portArgs.worldid = $vmNetInfo.WorldID + #Output the values to the temporary object + $tempout.VM = $vmobj.Name + $tempout.PortId = $esxcli.network.vm.port.list.Invoke($portArgs).PortId + $output += $tempout + } + } + } + + End { + + return $output + + } From 76820423a424f108dd5c3b79be5e4132c415677c Mon Sep 17 00:00:00 2001 From: Alan Comstock <31929022+Mr-Uptime@users.noreply.github.com> Date: Fri, 27 Oct 2017 09:16:39 -0500 Subject: [PATCH 07/29] Multipath to Round Robin on all FC disks in cluster This will configure multipath to round robin and IOPS to 1 on all disks in a cluster based upon the vendor type. This script is configured for 3par LUNs. Change $vendor for other storage types/vendors. --- Scripts/SetClusterMultiPathToRoundRobin.ps1 | 24 ++++++++------------- 1 file changed, 9 insertions(+), 15 deletions(-) diff --git a/Scripts/SetClusterMultiPathToRoundRobin.ps1 b/Scripts/SetClusterMultiPathToRoundRobin.ps1 index 97bf311..396b038 100644 --- a/Scripts/SetClusterMultiPathToRoundRobin.ps1 +++ b/Scripts/SetClusterMultiPathToRoundRobin.ps1 @@ -2,28 +2,22 @@ Script name: SetClusterMultiPathToRoundRobin.ps1 Created on: 09/14/2017 Author: Alan Comstock, @Mr_Uptime - Description: Set the MultiPath policy for FC devices to RoundRobin for all hosts in a cluster. + Description: Set the MultiPath policy for FC devices to RoundRobin and IOPS to 1 for all hosts in a cluster based upon the vendor tag. Dependencies: None known PowerCLI Version: VMware PowerCLI 6.5 Release 1 build 4624819 PowerShell Version: 5.1.14393.1532 OS Version: Windows 10 #> -#Check for any Fibre Channel devices that are not set to Round Robin in a cluster. -#Get-Cluster -Name CLUSTERNAME | Get-VMhost | Get-VMHostHba -Type "FibreChannel" | Get-ScsiLun -LunType disk | Where { $_.MultipathPolicy -notlike "RoundRobin" } | Select CanonicalName,MultipathPolicy - -#Set the Multipathing Policy to Round Robin for any Fibre Channel devices that are not Round Robin in a cluster -$cluster = Get-Cluster CLUSTERNAME -$hostlist = Get-VMHost -Location $cluster | Sort Name -$TotalHostCount = $hostlist.count -$hostincrement = 0 -while ($hostincrement -lt $TotalHostCount){ #Host Loop - $currenthost = $hostlist[$hostincrement].Name - Write-Host "Working on" $currenthost - $scsilun = Get-VMhost $currenthost | Get-VMHostHba -Type "FibreChannel" | Get-ScsiLun -LunType disk | Where { $_.MultipathPolicy -notlike "RoundRobin" } +$pathpolicy="RoundRobin" +$iops="1" +$vendor="3PARdata" +$AllESXHosts = Get-VMHost -Location CLUSTERNAME | Sort Name +Foreach ($esxhost in $AllESXHosts) { + Write-Host "Working on" $esxhost + $scsilun = Get-VMhost $esxhost | Get-VMHostHba -Type "FibreChannel" | Get-ScsiLun -LunType disk | Where-Object {$_.Vendor -like $vendor -and ($_.MultipathPolicy -notlike $pathpolicy -or $_.CommandsToSwitchPath -ne $iops)} if ($scsilun -ne $null){ - Set-ScsiLun -ScsiLun $scsilun -MultipathPolicy RoundRobin + Set-ScsiLun -ScsiLun $scsilun -MultipathPolicy $pathpolicy -CommandsToSwitchPath $iops } - $hostincrement++ #bump the host increment } #The End From dc523953cacedeeb0d00e22e6ea38b8ea9682111 Mon Sep 17 00:00:00 2001 From: Alan Comstock <31929022+Mr-Uptime@users.noreply.github.com> Date: Fri, 27 Oct 2017 09:25:47 -0500 Subject: [PATCH 08/29] Adds VLANs to an existing standard switch This script will add VLANs to an existing standard switch on a host. Information needed: $esxhost - Name of host $vswitch - Name of existing standard switch $vlanlist - List of all the VLANs you want to add to the switch --- Scripts/CreateVLANonStandardSwitch | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) create mode 100644 Scripts/CreateVLANonStandardSwitch diff --git a/Scripts/CreateVLANonStandardSwitch b/Scripts/CreateVLANonStandardSwitch new file mode 100644 index 0000000..d64b221 --- /dev/null +++ b/Scripts/CreateVLANonStandardSwitch @@ -0,0 +1,19 @@ +<# + Script name: CreateVLANonStandardSwitch.ps1 + Created on: 10/26/2017 + Author: Alan Comstock, @Mr_Uptime + Description: Adds VLANs to an existing standard switch + Dependencies: None known + PowerCLI Version: VMware PowerCLI 6.5 Release 1 build 4624819 + PowerShell Version: 5.1.14393.1532 + OS Version: Windows 10 +#> + +$esxhost="HOSTNAME" +$vswitch="vSwitch0" +$vlanlist=10,20,30,40,50 +Foreach ($vlan in $vlanlist) { + $portgroupname="VLAN " + $vlan + Get-VMHost $esxhost | Get-VirtualSwitch -name $vswitch | New-VirtualPortGroup -Name $portgroupname -VLanId $vlan +} +#The End From 77adef309d9774ebc3a558895c99650feffb9a76 Mon Sep 17 00:00:00 2001 From: William Lam Date: Sun, 29 Oct 2017 13:45:29 -0700 Subject: [PATCH 09/29] Adding NSXT Module --- Modules/NSXT/NSXT.psd1 | 18 +++ Modules/NSXT/NSXT.psm1 | 260 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 278 insertions(+) create mode 100644 Modules/NSXT/NSXT.psd1 create mode 100644 Modules/NSXT/NSXT.psm1 diff --git a/Modules/NSXT/NSXT.psd1 b/Modules/NSXT/NSXT.psd1 new file mode 100644 index 0000000..c3371b3 --- /dev/null +++ b/Modules/NSXT/NSXT.psd1 @@ -0,0 +1,18 @@ +@{ + ModuleToProcess = 'NSXT.psm1' + ModuleVersion = '1.0.0.0' + GUID = 'c72f4e3d-5d1d-498f-ba86-6fa03e4ae6dd' + Author = 'William Lam' + CompanyName = 'primp-industries.com' + Copyright = '(c) 2017. All rights reserved.' + Description = 'Powershell Module for NSX-T REST API Functions' + PowerShellVersion = '5.0' + FunctionsToExport = 'Get-NSXTComputeManager','Get-NSXTFabricNode','Get-NSXTFirewallRule','Get-NSXTIPPool','Get-NSXTLogicalSwitch','Get-NSXTManager','Get-NSXTTransportZone','Get-NSXTController' + PrivateData = @{ + PSData = @{ + Tags = @('NSX-T','REST') + LicenseUri = 'https://www.tldrlegal.com/l/mit' + ProjectUri = 'https://github.com/lamw/PowerCLI-Example-Scripts/tree/master/Modules/NSXT' + } + } +} \ No newline at end of file diff --git a/Modules/NSXT/NSXT.psm1 b/Modules/NSXT/NSXT.psm1 new file mode 100644 index 0000000..f8dcb49 --- /dev/null +++ b/Modules/NSXT/NSXT.psm1 @@ -0,0 +1,260 @@ +Function Get-NSXTController { + Param ( + [parameter(Mandatory=$false,ValueFromPipeline=$true)][string]$Id + ) + + $clusterNodeService = Get-NsxtService -Name "com.vmware.nsx.cluster.nodes" + $clusterNodeStatusService = Get-NsxtService -Name "com.vmware.nsx.cluster.nodes.status" + if($Id) { + $nodes = $clusterNodeService.get($Id) + } else { + $nodes = $clusterNodeService.list().results | where { $_.manager_role -eq $null } + } + + $results = @() + foreach ($node in $nodes) { + $nodeId = $node.id + $nodeName = $node.controller_role.control_plane_listen_addr.ip_address + $nodeStatusResults = $clusterNodeStatusService.get($nodeId) + + $tmp = [pscustomobject] @{ + Id = $nodeId; + Name = $nodeName; + ClusterStatus = $nodeStatusResults.control_cluster_status.control_cluster_status; + Version = $nodeStatusResults.version; + + } + $results+=$tmp + } + $results +} + +Function Get-NSXTFabricNode { + Param ( + [parameter(Mandatory=$false,ValueFromPipeline=$true)][string]$Id, + [Switch]$ESXi, + [Switch]$Edge + ) + + $fabricNodeService = Get-NsxtService -Name "com.vmware.nsx.fabric.nodes" + $fabricNodeStatusService = Get-NsxtService -Name "com.vmware.nsx.fabric.nodes.status" + if($Id) { + $nodes = $fabricNodeService.get($Id) + } else { + if($ESXi) { + $nodes = $fabricNodeService.list().results | where { $_.resource_type -eq "HostNode" } + } elseif ($Edge) { + $nodes = $fabricNodeService.list().results | where { $_.resource_type -eq "EdgeNode" } + } else { + $nodes = $fabricNodeService.list().results + } + } + + $results = @() + foreach ($node in $nodes) { + $nodeStatusResult = $fabricNodeStatusService.get($node.id) + + $tmp = [pscustomobject] @{ + Id = $node.id; + Name = $node.display_name; + Type = $node.resource_type; + Address = $node.ip_addresses; + NSXVersion = $nodeStatusResult.software_version + OS = $node.os_type; + Version = $node.os_version; + Status = $nodeStatusResult.host_node_deployment_status + ManagerStatus = $nodeStatusResult.mpa_connectivity_status + ControllerStatus = $nodeStatusResult.lcp_connectivity_status + } + $results+=$tmp + } + $results +} + +Function Get-NSXTIPPool { + Param ( + [parameter(Mandatory=$false,ValueFromPipeline=$true)][string]$Id + ) + + $ipPoolService = Get-NsxtService -Name "com.vmware.nsx.pools.ip_pools" + + if($Id) { + $ipPools = $ipPoolService.get($Id) + } else { + $ipPools = $ipPoolService.list().results + } + + $results = @() + foreach ($ipPool in $ipPools) { + $tmp = [pscustomobject] @{ + Id = $ipPool.Id; + Name = $ipPool.Display_Name; + Total = $ipPool.pool_usage.total_ids; + Free = $ipPool.pool_usage.free_ids; + Network = $ipPool.subnets.cidr; + Gateway = $ipPool.subnets.gateway_ip; + DNS = $ipPool.subnets.dns_nameservers; + RangeStart = $ipPool.subnets.allocation_ranges.start; + RangeEnd = $ipPool.subnets.allocation_ranges.end + } + $results+=$tmp + } + $results +} + +Function Get-NSXTTransportZone { + Param ( + [parameter(Mandatory=$false,ValueFromPipeline=$true)][string]$Id + ) + + $transportZoneService = Get-NsxtService -Name "com.vmware.nsx.transport_zones" + + if($Id) { + $transportZones = $transportZoneService.get($Id) + } else { + $transportZones = $transportZoneService.list().results + } + + $results = @() + foreach ($transportZone in $transportZones) { + $tmp = [pscustomobject] @{ + Id = $transportZone.Id; + Name = $transportZone.display_name; + Type = $transportZone.transport_type; + HostSwitchName = $transportZone.host_switch_name; + } + $results+=$tmp + } + $results +} + +Function Get-NSXTComputeManager { + Param ( + [parameter(Mandatory=$false,ValueFromPipeline=$true)][string]$Id + ) + + $computeManagerSerivce = Get-NsxtService -Name "com.vmware.nsx.fabric.compute_managers" + $computeManagerStatusService = Get-NsxtService -Name "com.vmware.nsx.fabric.compute_managers.status" + + if($Id) { + $computeManagers = $computeManagerSerivce.get($id) + } else { + $computeManagers = $computeManagerSerivce.list().results + } + + $results = @() + foreach ($computeManager in $computeManagers) { + $computeManagerStatus = $computeManagerStatusService.get($computeManager.Id) + + $tmp = [pscustomobject] @{ + Id = $computeManager.Id; + Name = $computeManager.display_name; + Server = $computeManager.server + Type = $computeManager.origin_type; + Version = $computeManagerStatus.Version; + Registration = $computeManagerStatus.registration_status; + Connection = $computeManagerStatus.connection_status; + } + $results+=$tmp + } + $results +} + +Function Get-NSXTLogicalSwitch { + Param ( + [parameter(Mandatory=$false,ValueFromPipeline=$true)][string]$Id + ) + + $logicalSwitchService = Get-NsxtService -Name "com.vmware.nsx.logical_switches" + $logicalSwitchSummaryService = Get-NsxtService -Name "com.vmware.nsx.logical_switches.summary" + + if($Id) { + $logicalSwitches = $logicalSwitchService.get($Id) + } else { + $logicalSwitches = $logicalSwitchService.list().results + } + + $results = @() + foreach ($logicalSwitch in $logicalSwitches) { + $transportZone = (Get-NSXTTransportZone -Id $logicalSwitch.transport_zone_id | Select Name | ft -HideTableHeaders | Out-String).trim() + $ports = $logicalSwitchSummaryService.get($logicalSwitch.id).num_logical_ports + + $tmp = [pscustomobject] @{ + Id = $logicalSwitch.Id; + Name = $logicalSwitch.display_name; + VLAN = $logicalSwitch.vlan; + AdminStatus = $logicalSwitch.admin_state; + Ports = $ports; + TransportZone = $transportZone; + } + $results+=$tmp + } + $results +} + +Function Get-NSXTFirewallRule { + Param ( + [parameter(Mandatory=$false,ValueFromPipeline=$true)][string]$Id + ) + + $firewallService = Get-NsxtService -Name "com.vmware.nsx.firewall.sections" + $firewallRuleService = Get-NsxtService -Name "com.vmware.nsx.firewall.sections.rules" + + if($Id) { + $firewallRuleSections = $firewallService.get($Id) + } else { + $firewallRuleSections = $firewallService.list().results + } + + $sectionResults = @() + foreach ($firewallRuleSection in $firewallRuleSections) { + $tmp = [pscustomobject] @{ + Id = $firewallRuleSection.Id; + Name = $firewallRuleSection.display_name; + Type = $firewallRuleSection.section_type; + Stateful = $firewallRuleSection.stateful; + RuleCount = $firewallRuleSection.rule_count; + } + $sectionResults+=$tmp + } + $sectionResults + + $firewallResults = @() + if($id) { + $firewallRules = $firewallRuleService.list($id).results + foreach ($firewallRule in $firewallRules) { + $tmp = [pscustomobject] @{ + Id = $firewallRule.id; + Name = $firewallRule.display_name; + Sources = if($firewallRule.sources -eq $null) { "ANY" } else { $firewallRule.sources}; + Destination = if($firewallRule.destinations -eq $null) { "ANY" } else { $firewallRule.destinations }; + Services = if($firewallRule.services -eq $null) { "ANY" } else { $firewallRule.services } ; + Action = $firewallRule.action; + AppliedTo = if($firewallRule.applied_tos -eq $null) { "ANY" } else { $firewallRule.applied_tos }; + Log = $firewallRule.logged; + } + $firewallResults+=$tmp + } + } + $firewallResults +} + +Function Get-NSXTManager { + $clusterNodeService = Get-NsxtService -Name "com.vmware.nsx.cluster.nodes" + + $nodes = $clusterNodeService.list().results + + $results = @() + foreach ($node in $nodes) { + if($node.manager_role -ne $null) { + $tmp = [pscustomobject] @{ + Id = $node.id; + Name = $node.display_name; + Address = $node.appliance_mgmt_listen_addr; + SHA256Thumbprint = $node.manager_role.api_listen_addr.certificate_sha256_thumbprint; + } + $results+=$tmp + } + } + $results +} \ No newline at end of file From df32c591484a3e90ef78086b19a73f9703253764 Mon Sep 17 00:00:00 2001 From: Unknown Date: Tue, 31 Oct 2017 11:17:36 -0400 Subject: [PATCH 10/29] Use the item in foreach rather than collection Error message should use $v rather than $vm --- Scripts/Get-VMNetworkPortId.ps1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Scripts/Get-VMNetworkPortId.ps1 b/Scripts/Get-VMNetworkPortId.ps1 index ed130a6..eeb2e62 100644 --- a/Scripts/Get-VMNetworkPortId.ps1 +++ b/Scripts/Get-VMNetworkPortId.ps1 @@ -30,7 +30,7 @@ foreach ($v in $vm) { #Validate the input is a valid VM $vmobj = Get-VM -Name $v -erroraction silentlycontinue - if (!$vmobj) {Write-Verbose "No VM found by the name $vm."} + if (!$vmobj) {Write-Verbose "No VM found by the name $v."} else { #Create a temporary object to store individual ouput $tempout = "" | select VM,PortId From 14256a32a87ee2bb607feba0bed4e3d6da3f6d77 Mon Sep 17 00:00:00 2001 From: daoyuanw Date: Tue, 14 Nov 2017 14:43:47 +0800 Subject: [PATCH 11/29] Add VMToolsManagment for VMTools upgrade, guest info query .etc --- .../VMToolsManagement/VMToolsManagement.psm1 | 1149 +++++++++++++++++ 1 file changed, 1149 insertions(+) create mode 100644 Modules/VMToolsManagement/VMToolsManagement.psm1 diff --git a/Modules/VMToolsManagement/VMToolsManagement.psm1 b/Modules/VMToolsManagement/VMToolsManagement.psm1 new file mode 100644 index 0000000..bbfdf5e --- /dev/null +++ b/Modules/VMToolsManagement/VMToolsManagement.psm1 @@ -0,0 +1,1149 @@ +# Script Module : VMToolsManagement +# Version : 1.0 + +# Copyright © 2017 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. + +New-VIProperty -Name ToolsBuildNumber -Object VirtualMachine -Value { + Param ($VM) + + foreach ($item in $VM.ExtensionData.Config.ExtraConfig.GetEnumerator()) { + if ($item.Key -eq "guestinfo.vmtools.buildNumber") { + $toolsBuildNumber = $item.value + break + } + } + + return $toolsBuildNumber +} -BasedOnExtensionProperty 'Config.ExtraConfig' -Force | Out-Null + +Function Get-VMToolsInfo { +<# +.SYNOPSIS + This cmdlet retrieves the VMTools info of specified virtual machines. + +.DESCRIPTION + This cmdlet retrieves the VMTools version and build number info of specified virtual machines. + +.PARAMETER VM + Specifies the virtual machines which you want to get the VMTools info of. + +.EXAMPLE + C:\PS> Import-Module .\VMToolsManagement.psm1 + C:\PS> $VCServer = Connect-VIServer -Server -User -Password + C:\PS> Get-VM -Server $VCServer | Get-VMToolsInfo + + Retrieves VMTools info of all virtual machines which run in the $VCServer vCetner Server. + +.EXAMPLE + C:\PS> Get-VM "*rhel*" | Get-VMToolsInfo + + Name ToolsVersion ToolsBuildNumber + ------ ------------ ---------------- + 111394-RHEL-6.8-0 10.2.0 6090153 + 111394-RHEL-6.8-1 9.0.15 + 111393-RHEL-Server-7.2 10.1.0 + + Retrieves VMTools info of virtual machines with name containing "rhel". + +.EXAMPLE + C:\PS> Get-VM -Location "MyClusterName" | Get-VMToolsInfo + + Retrieves VMTools info from virtual machines which run in the "MyClusterName" cluster. + +.EXAMPLE + C:\PS> Get-VMHost "MyESXiHostName" | Get-VM | Get-VMToolsInfo + + Retrieves VMTools info of virtual machines which run on the "MyESXiHostName" ESXi host. + +.NOTES + This cmdlet assumes that you are connected to at least one vCenter Server system. + The tools build number is not supported in VMTools before 10.2.0 + +.NOTES + Author : Daoyuan Wang + Author email : daoyuanw@vmware.com + Version : 1.0 + ==========Tested Against Environment========== + VMware vSphere Hypervisor(ESXi) Version : 6.5 (build 4564106) + VMware vCenter Server Version : 6.5 (build 4602587) + PowerCLI Version : PowerCLI 6.5 (build 4624819) + PowerShell Version : 5.1 +#> + + [CmdletBinding()] + + Param ( + [Parameter(Mandatory=$true, + ValueFromPipeLine = $true, + ValueFromPipelinebyPropertyName=$True, + Position = 0)] + [ValidateNotNullOrEmpty()] + [VMware.VimAutomation.ViCore.Types.V1.Inventory.VirtualMachine[]] $VM + ) + + Process { + Get-VM $VM | Select Name, @{Name="ToolsVersion"; Expression={$_.Guest.ToolsVersion}}, ToolsBuildNumber + } +} + +Function Get-VMToolsInstallLastError { +<# +.SYNOPSIS + This cmdlet retrieves the error code of last VMTools installation. + +.DESCRIPTION + This cmdlet retrieves the error code of last VMTools installation on specified virtual machines. + +.PARAMETER VM + Specifies the virtual machines which you want to get the error code of. + +.EXAMPLE + C:\PS> Import-Module .\VMToolsManagement.psm1 + C:\PS> $VCServer = Connect-VIServer -Server -User -Password + C:\PS> Get-VM -Server $VCServer | Get-VMToolsInstallLastError + + Retrieves the last VMTools installation error code of all virtual machines which run in the $VCServer vCetner Server. + +.EXAMPLE + C:\PS> Get-VM "*win*" | Get-VMToolsInstallLastError + + Name LastToolsInstallErrCode + ------ ----------------------- + 111167-Win-7-Sp1-64-Enterprise-NoTools + 111323-Windows-8.1U3-32-Enterprise-Tools + 111305-Windows-Server2016 1641 + + Retrieves the last VMTools installation error code of virtual machines with name containing "win". + +.EXAMPLE + C:\PS> Get-VM -Location "MyClusterName" | Get-VMToolsInstallLastError + + Retrieves the last VMTools installation error code of virtual machines which run in the "MyClusterName" cluster. + +.EXAMPLE + C:\PS> Get-VMHost "MyESXiHostName" | Get-VM | Get-VMToolsInstallLastError + + Retrieves the last VMTools installation error code of virtual machines which run on the "MyESXiHostName" ESXi host. + +.NOTES + This cmdlet assumes that you are connected to at least one vCenter Server system. + +.NOTES + Author : Daoyuan Wang + Author email : daoyuanw@vmware.com + Version : 1.0 + ==========Tested Against Environment========== + VMware vSphere Hypervisor(ESXi) Version : 6.5 (build 4564106) + VMware vCenter Server Version : 6.5 (build 4602587) + PowerCLI Version : PowerCLI 6.5 (build 4624819)(build 4624819) + PowerShell Version : 5.1 +#> + + [CmdletBinding()] + + Param ( + [Parameter(Mandatory=$true, + ValueFromPipeLine = $true, + ValueFromPipelinebyPropertyName=$True, + Position = 0)] + [ValidateNotNullOrEmpty()] + [VMware.VimAutomation.ViCore.Types.V1.Inventory.VirtualMachine[]] $VM + ) + + Process { + $result = @() + foreach ($_ in $VM) { + $errorCodeInfo = $_.ExtensionData.Config.ExtraConfig.GetEnumerator() | where {$_.Key -eq "guestinfo.toolsInstallErrCode"} + + $info = New-Object PSObject + $info | Add-Member -type NoteProperty -name VmName -value $_.Name + $info | Add-Member -type NoteProperty -name LastToolsInstallErrCode -value $errorCodeInfo.Value + + $result += $info + } + $result + } +} + +Function Get-VMToolsGuestInfo { +<# +.SYNOPSIS + This cmdlet retrieves the guest info of specified virtual machines. + +.DESCRIPTION + This cmdlet retrieves the guest info such as HostName, IP, ToolsStatus, ToolsVersion, + ToolsInstallType and GuestFamily of specified virtual machines. + +.PARAMETER VM + Specifies the virtual machines which you want to get the guest info of. + +.EXAMPLE + C:\PS> Import-Module .\VMToolsManagement.psm1 + C:\PS> $VCServer = Connect-VIServer -Server -User -Password + C:\PS> Get-VM -Server $VCServer | Get-VMToolsGuestInfo + + Retrieves guest info of all virtual machines which run in the $VCServer vCetner Server. + +.EXAMPLE + C:\PS> Get-VM "*win*" | Get-VMToolsGuestInfo + + Name : 111323-Windows-8.1U3-32-Enterprise-Tools + HostName : win81u3 + IP : + ToolsStatus : toolsNotRunning + ToolsVersion : 10.2.0 + ToolsInstallType : guestToolsTypeMSI + GuestFamily : windowsGuest + VMPowerState : PoweredOff + + Name : 111305-Windows-Server2016 + HostName : WIN-ULETOOSSB7U + IP : 10.160.59.99 + ToolsStatus : toolsOk + ToolsVersion : 10.1.0 + ToolsInstallType : guestToolsTypeMSI + GuestFamily : windowsGuest + VMPowerState : PoweredOn + + Retrieves guest info of virtual machines with name containing "win". + +.EXAMPLE + C:\PS> Get-VM -Location "MyClusterName" | Get-VMToolsGuestInfo + + Retrieves guest info of virtual machines which run in the "MyClusterName" cluster. + +.EXAMPLE + C:\PS> Get-VMHost "MyESXiHostName" | Get-VM | Get-VMToolsGuestInfo + + Retrieves guest info of virtual machines which run on the "MyESXiHostName" ESXi host. + +.NOTES + This cmdlet assumes that you are connected to at least one vCenter Server system. + +.NOTES + Author : Daoyuan Wang + Author email : daoyuanw@vmware.com + Version : 1.0 + ==========Tested Against Environment========== + VMware vSphere Hypervisor(ESXi) Version : 6.5 (build 4564106) + VMware vCenter Server Version : 6.5 (build 4602587) + PowerCLI Version : PowerCLI 6.5 (build 4624819)(build 4624819) + PowerShell Version : 5.1 +#> + + [CmdletBinding()] + + Param ( + [Parameter(Mandatory=$true, + ValueFromPipeLine = $true, + ValueFromPipelinebyPropertyName=$True, + Position = 0)] + [ValidateNotNullOrEmpty()] + [VMware.VimAutomation.ViCore.Types.V1.Inventory.VirtualMachine[]] $VM + ) + + Process { + Get-VM $VM | Select Name, @{Name="HostName"; Expression={$_.Guest.HostName}}, + @{Name="IP"; Expression={$_.Guest.ExtensionData.IpAddress}}, + @{Name="ToolsStatus"; Expression={$_.Guest.ExtensionData.ToolsStatus}}, + @{Name="ToolsVersion"; Expression={$_.Guest.ToolsVersion}}, + @{Name="ToolsInstallType"; Expression={$_.Guest.ExtensionData.ToolsInstallType}}, + @{Name="GuestFamily"; Expression={$_.Guest.GuestFamily}}, + PowerState + } +} + +Function Get-VMByToolsInfo { +<# +.SYNOPSIS + This cmdlet retrieves the virtual machines with specified VMTools info. + +.DESCRIPTION + This cmdlet retrieves the virtual machines with specified VMTools version, + running status or version status. + +.PARAMETER VM + Specifies the virtual machines which you want to query VMTools status of. + +.PARAMETER ToolsVersion + Specifies the VMTools version. + +.PARAMETER ToolsRunningStatus + Specifies the VMTools running status. + +.PARAMETER ToolsVersionStatus + Specifies the VMTools version status. + +.EXAMPLE + C:\PS> Import-Module .\VMToolsManagement.psm1 + C:\PS> $VCServer = Connect-VIServer -Server -User -Password + C:\PS> Get-VM -Server $VCServer | Get-VMByToolsInfo + + Retrieves the virtual machines with VMTools not running in vCetner Server $VCServer. + +.EXAMPLE + C:\PS> Get-VM | Get-VMByToolsInfo -ToolsRunningStatus guestToolsNotRunning + + Name PowerState Num CPUs MemoryGB + ---- ---------- -------- -------- + 111394-RHEL-6.8-1 PoweredOff 4 2.000 + + Retrieves all the virtual machines with VMTools not running. + +.EXAMPLE + C:\PS> Get-VM | Get-VMByToolsInfo -ToolsVersion '10.1.0' + + Name PowerState Num CPUs MemoryGB + ---- ---------- -------- -------- + 111394-RHEL-6.8-1 PoweredOff 4 2.000 + + Retrieves the virtual machines with VMTools version 10.1.0. + +.EXAMPLE + C:\PS> Get-VM -Location "MyClusterName" | Get-VMByToolsInfo -ToolsVersionStatus guestToolsNeedUpgrade + + Retrieves the virtual machines with VMTools that need to upgrade in the "MyClusterName" cluster. + +.EXAMPLE + C:\PS> Get-VMHost "MyESXiHostName" | Get-VM | Get-VMByToolsInfo -ToolsRunningStatus guestToolsRunning -ToolsVersionStatus guestToolsNeedUpgrade + + Retrieves the virtual machines with VMTools that need to upgrade on the "MyESXiHostName" ESXi host. + +.NOTES + This cmdlet assumes that you are connected to at least one vCenter Server system. + +.NOTES + Author : Daoyuan Wang + Author email : daoyuanw@vmware.com + Version : 1.0 + ==========Tested Against Environment========== + VMware vSphere Hypervisor(ESXi) Version : 6.5 (build 4564106) + VMware vCenter Server Version : 6.5 (build 4602587)(build 4602587) + PowerCLI Version : PowerCLI 6.5 (build 4624819) + PowerShell Version : 5.1 +#> + + [CmdletBinding()] + + Param ( + [Parameter(Mandatory=$true, + ValueFromPipeLine = $true, + ValueFromPipelinebyPropertyName=$True, + Position = 0)] + [ValidateNotNullOrEmpty()] + [VMware.VimAutomation.ViCore.Types.V1.Inventory.VirtualMachine[]] $VM, + + [Parameter(Mandatory=$false)] + [String] $ToolsVersion, + + [Parameter(Mandatory=$false)] + [ValidateSet("guestToolsRunning", + "guestToolsNotRunning", + "guestToolsExecutingScripts")] + [String] $ToolsRunningStatus, + + [Parameter(Mandatory=$false)] + [ValidateSet("guestToolsNotInstalled", + "guestToolsNeedUpgrade", + "guestToolsCurrent", + "guestToolsUnmanaged")] + [String] $ToolsVersionStatus + ) + + Process { + $vmList = Get-VM $VM + + if ((-not $ToolsVersion) -and (-not $ToolsRunningStatus) -and (-not $ToolsVersionStatus)) { + Throw "Please specify at lease one parameter: ToolsVersion, ToolsRunningStatus or ToolsVersionStatus" + } + + if ($ToolsVersion) { + $vmList = $vmList | Where {$_.Guest.ToolsVersion -like $ToolsVersion} + } + + if ($ToolsRunningStatus) { + $vmList = $vmList | Where {$_.Guest.ExtensionData.ToolsRunningStatus -eq $ToolsRunningStatus} + } + + if ($ToolsVersionStatus) { + $vmList = $vmList | Where {$_.Guest.ExtensionData.ToolsVersionStatus -eq $ToolsVersionStatus} + } + + $vmList + } +} + +Function Set-VMToolsUpgradePolicy { +<# +.SYNOPSIS + This cmdlet sets the VMTool's upgrade policy to "upgradeAtPowerCycle". + +.DESCRIPTION + This cmdlet sets the VMTool's upgrade policy to "upgradeAtPowerCycle" of specified virtual machines. + +.PARAMETER VM + Specifies the virtual machines which you want to set the VMTool's upgrade policy of. + +.EXAMPLE + C:\PS> Import-Module .\VMToolsManagement.psm1 + C:\PS> $VCServer = Connect-VIServer -Server -User -Password + C:\PS> Get-VM -Server $VCServer | Set-VMToolsUpgradePolicy + + Sets VMTool's upgrade policy to "upgradeAtPowerCycle" of all virtual machines in the $VCServer vCetner Server. + +.EXAMPLE + C:\PS> Get-VM "*win*" | Set-VMToolsUpgradePolicy + + Sets VMTool's upgrade policy to "upgradeAtPowerCycle" of virtual machines with name containing "win". + +.EXAMPLE + C:\PS> Get-VM -Location "MyClusterName" | Set-VMToolsUpgradePolicy + + Sets VMTool's upgrade policy to "upgradeAtPowerCycle" of virtual machines in the "MyClusterName" cluster. + +.EXAMPLE + C:\PS> Get-VMHost "MyESXiHostName" | Get-VM | Set-VMToolsUpgradePolicy + + Sets VMTool's upgrade policy to "upgradeAtPowerCycle" of virtual machines on the "MyESXiHostName" ESXi host. + +.NOTES + This cmdlet assumes that you are connected to at least one vCenter Server system. + +.NOTES + Author : Daoyuan Wang + Author email : daoyuanw@vmware.com + Version : 1.0 + ==========Tested Against Environment========== + VMware vSphere Hypervisor(ESXi) Version : 6.5 (build 4564106) + VMware vCenter Server Version : 6.5 (build 4602587) + PowerCLI Version : PowerCLI 6.5 (build 4624819) + PowerShell Version : 5.1 +#> + + [CmdletBinding()] + + Param ( + [Parameter(Mandatory=$true, + ValueFromPipeLine = $true, + ValueFromPipelinebyPropertyName=$True, + Position = 0)] + [ValidateNotNullOrEmpty()] + [VMware.VimAutomation.ViCore.Types.V1.Inventory.VirtualMachine[]] $VM + ) + Begin { + $UpgradePolicy = "upgradeAtPowerCycle" + $vmConfigSpec = New-Object VMware.Vim.VirtualMachineConfigSpec + $vmConfigSpec.Tools = New-Object VMware.Vim.ToolsConfigInfo + $vmConfigSpec.Tools.ToolsUpgradePolicy = $UpgradePolicy + } + + Process { + foreach ($_ in $VM) { + # Get current setting + $vmView = Get-View $_ -Property Config.Tools.ToolsUpgradePolicy + # Change if VMTools upgrade policy is not "upgradeAtPowerCycle" + if ($vmView.Config.Tools.ToolsUpgradePolicy -ne $UpgradePolicy) { + Write-Verbose "Applying 'upgradeAtPowerCycle' setting to $($_.Name)..." + $vmView.ReconfigVM($vmConfigSpec) + } + } + } +} + +Function Invoke-VMToolsListProcessInVM { +<# +.Synopsis + This cmdlet lists the processes in the virtual machine. + +.Description + This cmdlet lists the running processes in the virtual machine. + +.PARAMETER VM + Specifies the virtual machine which you want to list the processes of. + +.Parameter GuestUser + Specifies the user name you want to use for authenticating with the guest OS. + +.Parameter GuestPassword + Specifies the password you want to use for authenticating with the guest OS. + +.Example + C:\PS> Import-Module .\VMToolsManagement.psm1 + C:\PS> $SampleVM = get-vm "MyVMName" + C:\PS> Invoke-VMToolsListProcessInVM -VM $SampleVM -GuestUser -GuestPassword + + ScriptOutput + ----------------------------------------------------------------------------------------------------------------------- + | USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND + | root 1 0.0 0.0 19360 1556 ? Ss Jul20 0:02 /sbin/init + | root 2 0.0 0.0 0 0 ? S Jul20 0:00 [kthreadd] + | root 3 0.0 0.0 0 0 ? S Jul20 0:06 [migration/0] + | root 4 0.0 0.0 0 0 ? S Jul20 0:00 [ksoftirqd/0] + | root 5 0.0 0.0 0 0 ? S Jul20 0:00 [stopper/0] + ...... + + List the processes in the "MyVMName" VM. + +.NOTES + This cmdlet lists processes in the guest OS of virtual machine. + A VMTools should already be running in the guest OS. + +.NOTES + Author : Daoyuan Wang + Author email : daoyuanw@vmware.com + Version : 1.0 + ==========Tested Against Environment========== + VMware vSphere Hypervisor(ESXi) Version : 6.5 (build 4564106) + VMware vCenter Server Version : 6.5 (build 4602587) + PowerCLI Version : PowerCLI 6.5 (build 4624819) + PowerShell Version : 5.1 + Guest OS : RHEL6.8, Windows7 +#> + + [CmdletBinding()] + + Param ( + [Parameter(Mandatory=$true, + ValueFromPipeLine = $true, + ValueFromPipelinebyPropertyName=$True, + Position = 0)] + [ValidateNotNullOrEmpty()] + [VMware.VimAutomation.ViCore.Types.V1.Inventory.VirtualMachine] $VM, + + [Parameter(Mandatory=$true)] + [ValidateNotNullOrEmpty()] + [String] $GuestUser, + + [Parameter(Mandatory=$true)] + [AllowEmptyString()] + [String] $GuestPassword + ) + + Process { + $vmView = Get-VM $VM | Get-View -Property Guest + if ($vmView.Guest.State -eq 'NotRunning') { + Write-Error "$VM is Not Running, unable to list the processes!" + return + } + + if ($vmView.Guest.GuestFamily -match 'windows') { + $command = 'Get-Process' + } elseif ($vmView.Guest.GuestFamily -match 'linux') { + $command = 'ps aux' + } else { + $command = 'ps' + } + + Invoke-VMScript -VM $VM -ScriptText $command -GuestUser $GuestUser -GuestPassword $GuestPassword + } +} + +Function Update-VMToolsImageLocation { +<# +.Synopsis + This cmdlet updates the link /productLocker in ESXi host. + +.Description + This cmdlet updates the link /productLocker in ESXi host directly to avoid host reboot. + +.Parameter VMHost + Specifies the ESXi host on which you want to update the /productLocker link. + +.Parameter HostUser + Specifies the user name you want to use for authenticating with the ESXi host. + +.Parameter HostPassword + Specifies the password you want to use for authenticating with the ESXi host. + +.Parameter ImageLocation + Specifies the new image location where you want /producterLocker to link. + +.Example + C:\PS> Import-Module .\VMToolsManagement.psm1 + C:\PS> $SampleHost = get-vmhost + C:\PS> Update-VMToolsImageLocation -VmHost $SampleHost -HostUser 'root' -HostPassword -ImageLocation '/locker/packages/6.5.0/' + + Update link /productLocker successfully. + + Update the link /producterLocker on $SampleHost to point to '/locker/packages/6.5.0/'. + +.NOTES + This cmdlet connects to ESXi host to execute shell command directly. + Make sure the SSH service on ESXi host is enabled, and a SSH library(Posh-SSH or SSH-Sessions etc.) + for powershell is already installed on client where you call This cmdlet. + You can instal Posh-SSH by executing: + iex (New-Object Net.WebClient).DownloadString("https://gist.github.com/darkoperator/6152630/raw/c67de4f7cd780ba367cccbc2593f38d18ce6df89/instposhsshdev") + For SSH-Sessions installation and usage, please refer to + http://www.powershelladmin.com/wiki/SSH_from_PowerShell_using_the_SSH.NET_library + + +.NOTES + Author : Daoyuan Wang + Author email : daoyuanw@vmware.com + Version : 1.0 + ==========Tested Against Environment========== + VMware vSphere Hypervisor(ESXi) Version : 6.5 (build 4564106) + VMware vCenter Server Version : 6.5 (build 4602587) + PowerCLI Version : PowerCLI 6.5 (build 4624819) + PowerShell Version : 5.1 +#> + + [CmdletBinding()] + + Param ( + [Parameter(Mandatory=$true, + ValueFromPipeLine = $true, + ValueFromPipelinebyPropertyName=$True, + Position = 0)] + [VMware.VimAutomation.ViCore.Types.V1.Inventory.VMHost] $VMHost, + + [Parameter(Mandatory=$true)] + [String] $HostUser, + + [Parameter(Mandatory=$true)] + [AllowEmptyString()] + [String] $HostPassword, + + [Parameter(Mandatory=$true)] + [String] $ImageLocation + ) + + Process { + if (-not (Get-Command New-SSHSession)) { + Throw "This cmdlet depends on SSH library. Please ensure a SSH library is already installed!" + } + + $password = new-object System.Security.SecureString + if ($HostPassword) { + $password = ConvertTo-SecureString -AsPlainText $HostPassword -Force + } + + $crendential = New-Object System.Management.Automation.PSCredential -ArgumentList $HostUser, $password + $sshSession = New-SSHSession -ComputerName $VMHost -Credential $crendential -Force + + $result = Invoke-SshCommand -SSHSession $sshSession -Command "readlink /productLocker" -EnsureConnection:$false + Write-Verbose "The link /productLocker before change: $($result.Output)" + + $command = "rm /productLocker && ln -s $ImageLocation /productLocker" + Write-Verbose "Updating /productLocker on $VMHost..." + $result = Invoke-SshCommand -SSHSession $sshSession -Command $command -EnsureConnection:$false + if ($result.ExitStatus -eq 0) { + Write-Host "Update link /productLocker successfully." -ForegroundColor Green + } else { + Write-Error "Failed to update link /productLocker: $($result.Error)" + } + + $result = Invoke-SshCommand -SSHSession $sshSession -Command "readlink /productLocker" -EnsureConnection:$false + Write-Verbose "The link /productLocker after change: $($result.Output)" + } +} + +Function Update-VMToolsConfInVM { +<# +.Synopsis + This cmdlet updates the tools.conf content in guest OS. + +.Description + This cmdlet copies the tools.conf in gueset OS of virtual machine to localhost, + then updates it locally by setting "vmtoolsd.level = info" and copies it back to the guest OS. + +.PARAMETER VM + Specifies the virtual machine to update. + +.Parameter GuestUser + Specifies the user name you want to use for authenticating with the guest OS. + +.Parameter GuestPassword + Specifies the password you want to use for authenticating with the guest OS. + +.Example + C:\PS> Import-Module .\VMToolsManagement.psm1 + C:\PS> $SampleVM = get-vm "MyVMName" + C:\PS> Update-VMToolsConfInVM -VM $SampleVM -GuestUser -GuestPassword + + Update tools.conf of 111394-RHEL-6.8-0 successfully. + + Updates the tools.conf in $SampleVM, changes the vmtoolsd log level to info ("vmtoolsd.level = info") for example. + +.NOTES + This cmdlet updates the tools.conf in guest OS. A VMTools should already be running in the guest OS. + +.NOTES + Author : Daoyuan Wang + Author email : daoyuanw@vmware.com + Version : 1.0 + ==========Tested Against Environment========== + VMware vSphere Hypervisor(ESXi) Version : 6.5 (build 4564106) + VMware vCenter Server Version : 6.5 (build 4602587) + PowerCLI Version : PowerCLI 6.5 (build 4624819) + PowerShell Version : 5.1 +#> + + [CmdletBinding()] + + Param ( + [Parameter(Mandatory=$true, + ValueFromPipeLine = $true, + ValueFromPipelinebyPropertyName=$True, + Position = 0)] + [ValidateNotNullOrEmpty()] + [VMware.VimAutomation.ViCore.Types.V1.Inventory.VirtualMachine] $VM, + + [Parameter(Mandatory=$true)] + [String] $GuestUser, + + [Parameter(Mandatory=$true)] + [AllowEmptyString()] + [String] $GuestPassword + ) + + Process { + $vmGuest = Get-VMGuest $VM + $OsName = $vmGuest.OSFullName + $guestToolsConfFile = "" + $localToolsConfFile = ".\tools.conf" + + # Determine the tools.conf path in guest OS + if (($OsName -match "Linux") ` + -or ($OsName -match "FreeBSD") ` + -or ($OsName -match "Solaris")) { + $guestToolsConfFile = '/etc/vmware-tools/tools.conf' + } elseif (($OsName -match "Windows Server 2003") ` + -or ($OsName -match "Windows Server 2000") ` + -or ($OsName -match "Windows XP")) { + $guestToolsConfFile = 'C:\Documents and Settings\All Users\Application Data\VMware\VMware Tools\tools.conf' + } elseif ($OsName -match "Windows") { + $guestToolsConfFile = 'C:\ProgramData\VMware\VMware Tools\tools.conf' + } elseif ($OsName -match "Mac") { + $guestToolsConfFile = '/Library/Application Support/VMware Tools/tools.conf' + } else { + Throw "Unknown tools.conf path on OS: $OsName" + } + + # Get the tools.conf from guest OS to localhost, ignore the error if tools.conf was not found in guest OS + Write-Verbose "Copy tools.conf from $VM to localhost..." + $lastError = $Error[0] + Copy-VMGuestFile -Source $guestToolsConfFile -Destination $localToolsConfFile -VM $VM -GuestToLocal ` + -GuestUser $GuestUser -GuestPassword $GuestPassword -Force -ErrorAction:SilentlyContinue + + # The tools.conf doesn't exist in guest OS, create an empty one locally + if (($Error[0] -ne $lastError) -and ($Error[0] -notmatch 'tools.conf was not found')) { + Write-Error "Failed to copy tools.conf from $VM" + return + } elseif (-not (Test-Path $localToolsConfFile)) { + Set-Content $localToolsConfFile $null + } + + ############################################################################# + # Updates tools.conf by setting vmtoolsd.level = info, just for example. + ############################################################################# + $confContent = Get-Content $localToolsConfFile + $updatedContent = "vmtoolsd.level = info" + + Write-Verbose "Editing tools.conf (set 'vmtoolsd.level = info' for example)..." + if ($confContent -match "vmtoolsd\.level") { + $confContent -replace "vmtoolsd\.level.*", $updatedContent | Set-Content $localToolsConfFile + } elseif ($confContent -match "logging") { + Add-Content $localToolsConfFile $updatedContent + } else { + Add-Content $localToolsConfFile "[logging]`nlog=true" + Add-Content $localToolsConfFile $updatedContent + } + + # Upload the changed tools.conf to guest OS + try { + Write-Verbose "Copy local tools.conf to $VM..." + Copy-VMGuestFile -Source $localToolsConfFile -Destination $guestToolsConfFile -VM $VM -LocalToGuest ` + -GuestUser $GuestUser -GuestPassword $GuestPassword -Force -ErrorAction:Stop + } catch { + Write-Error "Failed to update tools.conf of $VM" + return + } + Write-Host "The tools.conf updated in $VM successfully." -ForegroundColor Green + } +} + +Function Invoke-VMToolsVIBInstall { +<# +.SYNOPSIS + This cmdlet installs VMTool VIB in ESXi hosts. + +.DESCRIPTION + This cmdlet installs VMTool VIB in specified ESXi hosts. + +.PARAMETER VMHost + Specifies the ESXi hosts which you want to install VMTool VIB in. + +.PARAMETER ToolsVibUrl + Specifies the URL of VMTools VIB package which you want to install in ESXi hosts. + +.EXAMPLE + C:\PS> Import-Module .\VMToolsManagement.psm1 + C:\PS> $VCServer = Connect-VIServer -Server -User -Password . + C:\PS> $viBurl = "http:///VMware_locker_tools-light_6.5.0-10.2.0.6085460.vib" + C:\PS> Get-VMHost -Server $VCServer | Invoke-VMToolsVIBInstall -ToolsVibUrl $viBurl + + Install VMTool VIB in $VCServer. + +.EXAMPLE + C:\PS> Invoke-VMToolsVIBInstall -VMHost "MyESXiHostName" -ToolsVibUrl $viBurl + + Installs VMTools VIB package successfully. + + Installs VMTool VIB in the "MyESXiHostName" ESXi host. + +.EXAMPLE + C:\PS> Get-VMHost -Location "MyClusterName" | Invoke-VMToolsVIBInstall -ToolsVibUrl $vib + + Installs VMTool VIB in ESXi host of the "MyClusterName" cluster. + +.NOTES + This cmdlet assumes that you are connected to at least one vCenter Server system. + +.NOTES + Author : Daoyuan Wang + Author email : daoyuanw@vmware.com + Version : 1.0 + ==========Tested Against Environment========== + VMware vSphere Hypervisor(ESXi) Version : 6.5 (build 4564106) + VMware vCenter Server Version : 6.5 (build 4602587) + PowerCLI Version : PowerCLI 6.5 (build 4624819) + PowerShell Version : 5.1 +#> + + [CmdletBinding()] + + Param ( + [Parameter(Mandatory=$true, + ValueFromPipeLine = $true, + ValueFromPipelinebyPropertyName=$True, + Position = 0)] + [VMware.VimAutomation.ViCore.Types.V1.Inventory.VMHost[]] $VMHost, + + [Parameter(Mandatory=$true)] + [String] $ToolsVibUrl + ) + + Process { + foreach ($_ in $VMHost) { + $esxcli = Get-EsxCLI -VMHost $_ -V2 + + $result = $esxcli.software.vib.list.Invoke() | where {$_.name -match 'tools'} + Write-Verbose "Existing tools VIB on $_ before installing: $($result.Name)_$($result.Version)" + + # Install VIBs + Write-Verbose "Installing $ToolsVibUrl on $($_.Name)..." + $Error.Clear() + $cliArgs = $esxcli.software.vib.install.CreateArgs() + $cliArgs.viburl = $ToolsVibUrl + $cliArgs.nosigcheck = $true + $cliArgs.force = $true + $result = $esxcli.software.vib.install.Invoke($cliArgs) + if ($Error) { + Write-Error "Failed to install VMTools VIB package!" + } else { + Write-Verbose $result.Message + $result = $esxcli.software.vib.list.Invoke() | where {$_.name -match 'tools'} + Write-Verbose "Tools VIB on $_ after installing: $($result.Name)_$($result.Version)" + Write-Host "VMTools VIB package installed on $_ successfully." -ForegroundColor Green + } + } + } +} + +Function Invoke-VMToolsUpgradeInVMs { +<# +.SYNOPSIS + This cmdlet upgrades VMTools to the version bundled by ESXi host. + +.DESCRIPTION + This cmdlet upgrades VMTools of specified virtual machines to the version + bundled by ESXi host. You can also specify the number of virtual machines + to upgrade in parallel. + +.PARAMETER VM + Specifies the virtual machines you want to upgrade VMTools of. + +.PARAMETER GuestOSType + Specifies the guest OS type of the virtual machines. + +.PARAMETER VersionToUpgrade + Specifies the current running VMTools version of virtual machines. + +.PARAMETER MaxParallelUpgrades + Specifies the max virtual machine numbers to upgrade in parallel. + +.EXAMPLE + C:\PS> Import-Module .\VMToolsManagement.psm1 + C:\PS> $VCServer = Connect-VIServer -Server -User -Password + C:\PS> Get-VM -Server $VCServer | Invoke-VMToolsUpgradeInVMs -MaxParallelUpgrades 5 + + Upgrades VMTools of all virtual machines in the $VCServer vCetner Server, 5 at a time in parallel. + +.EXAMPLE + C:\PS> Get-VM | Invoke-VMToolsUpgradeInVMs -GuestOSType windows -MaxParallelUpgrades 1 | ft -Autosize + + Upgrade result: + + VmName UpgradeResult ToolsVersion ToolsVersionStatus TotalSeconds Message + ------ ------------- ------------ ------------------ ------------ ------- + 111167-Win-7-Sp1-64-Enterprise-NoTools-2 Completed 10.1.0 guestToolsCurrent 102 Upgrade VMTools successfully + 111393-RHEL-Server-7.2 Skipped 10.0.0 guestToolsNeedUpgrade 0 Guest OS type does not meet condtion 'windows' + 111305-Windows-Server2016 Completed 10.1.0 guestToolsCurrent 144 Upgrade VMTools successfully + + Upgrades VMTools of windows virtual machines one by one. + +.EXAMPLE + C:\PS> Get-VM -Location "MyClusterName" | Invoke-VMToolsUpgradeInVMs -MaxParallelUpgrades 2 | ft -Autosize + + Upgrade result: + + VmName UpgradeResult ToolsVersion ToolsVersionStatus TotalSeconds Message + ------ ------------- ------------ ------------------ ------------ ------- + 111167-Win-7-Sp1-64-Enterprise-NoTools-2 Failed 10.0.0 guestToolsNeedUpgrade 0 The required VMware Tools ISO image does not exist or is inaccessible. + 111393-RHEL-Server-7.2 Completed 10.1.0 guestToolsCurrent 100 Upgrade VMTools successfully + + Upgrades VMTools of virtual machines in the "MyClusterName" cluster, 2 at a time. + +.EXAMPLE + C:\PS> Get-VMHost "MyESXiHostName" | Get-VM | Invoke-VMToolsUpgradeInVMs -MaxParallelUpgrades 5 + + Upgrades VMTools of virtual machines on the "MyESXiHostName" ESXi host, 5 at a time. + +.NOTES + This cmdlet assumes an old VMTools is already running in the virtual machine. + +.NOTES + Author : Daoyuan Wang + Author email : daoyuanw@vmware.com + Version : 1.0 + ==========Tested Against Environment========== + VMware vSphere Hypervisor(ESXi) Version : 6.5 (build 4564106) + VMware vCenter Server Version : 6.5 (build 4602587) + PowerCLI Version : PowerCLI 6.5 (build 4624819) + PowerShell Version : 5.1 +#> + + [CmdletBinding()] + + Param ( + [Parameter(Mandatory=$true, + ValueFromPipeLine = $true, + ValueFromPipelinebyPropertyName=$True, + Position = 0)] + [ValidateNotNullOrEmpty()] + [VMware.VimAutomation.ViCore.Types.V1.Inventory.VirtualMachine[]] $VM, + + [Parameter(Mandatory=$false)] + [ValidateSet("linux", "windows")] + [String] $GuestOSType, + + [Parameter(Mandatory=$false)] + [String] $VersionToUpgrade, + + [Parameter(Mandatory=$false)] + [ValidateRange(1, 5)] + [Int] $MaxParallelUpgrades = 1 + ) + + Begin { + $RunspacePool = [runspacefactory]::CreateRunspacePool( + 1, #Min Runspaces + $MaxParallelUpgrades #Max Runspaces + ) + + $RunspacePool.Open() + + $jobs = New-Object System.Collections.ArrayList + $result = @() + } + + Process { + foreach ($_ in $VM) { + $vmView = Get-View $_ -Property Guest + $toolsVersion = $_.Guest.ToolsVersion + $toolsVersionStatus = $vmView.Guest.ToolsVersionStatus + + # Skip if VMTools doesn't need to upgrade + if ($toolsVersionStatus -ne "guestToolsNeedUpgrade") { + Write-Host "No VMTools need to upgrade!`nVM: '$_', ToolsVersionStatus: '$toolsVersionStatus'" + $result += [pscustomobject]@{ + VmName = $_.Name + UpgradeResult = "Skipped" + ToolsVersion = $toolsVersion + ToolsVersionStatus = $toolsVersionStatus + TotalSeconds = 0 + Message = "No VMTools need to upgrade!" + } + continue + } + + # Skip if current VMTools doesn't meet to specified version + if ($VersionToUpgrade -and ($toolsVersion -notmatch $VersionToUpgrade)) { + Write-Host "Current ToolsVersion in $_ is: $toolsVersion,"` + "does not meet condtion `'$VersionToUpgrade`', skipping it..." -ForegroundColor Yellow + $result += [pscustomobject]@{ + VmName = $_.Name + UpgradeResult = "Skipped" + ToolsVersion = $toolsVersion + ToolsVersionStatus = $toolsVersionStatus + TotalSeconds = 0 + Message = "Current VMTools version does not meet condtion `'$VersionToUpgrade`'" + } + continue + } + + # Create a thread to upgrade VMTools for each virtual machine + $PSThread = [powershell]::Create() + $PSThread.RunspacePool = $RunspacePool + + # Script content to upgrade VMTools + $PSThread.AddScript({ + Param ( + $vcServer, + $session, + $vmId, + $GuestOSType + ) + # Load PowerCLI module and connect to VCServer, as child thread environment is independent with parent + if(-not $global:DefaultVIServer) { + $moduleName = "vmware.vimautomation.core" + if(-not (Get-Module | Where {$_.name -eq $moduleName})) { + try { + Import-Module $moduleName -ErrorAction SilentlyContinue | Out-Null + } + catch { + Throw "Failed to load PowerCLI module('$moduleName')" + } + } + try { + $server = Connect-VIServer -Server $vcserver -session $session -Force + } + catch { + Throw "Failed to connect to VI server: $vcserver" + } + } + + # Retrieves VM + $vm = Get-VM -Id $vmId + + $ThreadID = [appdomain]::GetCurrentThreadId() + Write-Verbose “Thread[$ThreadID]: Beginning Update-Tools for $vm” + + if ($vm.PowerState -ne 'PoweredOn') { + Write-Host "Powering on VM: $vm..." + Start-VM $vm | Out-Null + $vm = Get-VM $vm + } + + # Wait for OS and VMTools starting up + $timeOut = 60*10 #seconds + $refreshInterval = 5 #seconds + $count = $timeOut/$refreshInterval + while (($vm.Guest.ExtensionData.ToolsRunningStatus -ne "guestToolsRunning") ` + -or (-not $vm.Guest.GuestFamily)) { + $count -= 1 + if ($count -lt 0) { + Write-Error "VMTools doesn't start up in $timeOut seconds, please check if $vm is hung!" + break + } + Write-Verbose "Waiting for VMTools running in $vm before upgrading..." + Start-Sleep -Seconds $refreshInterval + } + + # Skip if virtual machine doesn't meet specified guest OS type + if ($GuestOSType -and ($vm.Guest.GuestFamily -notmatch $GuestOSType)) { + Write-Host "GuestFamily of $vm is: $($vm.Guest.GuestFamily),"` + "does not meet condition `'$GuestOSType`', skipping it..." -ForegroundColor Yellow + # upgrade result + [pscustomobject]@{ + VmName = $vm.Name + UpgradeResult = "Skipped" + ToolsVersion = $vm.Guest.ToolsVersion + ToolsVersionStatus = $vm.Guest.ExtensionData.ToolsVersionStatus + TotalSeconds = 0 + Message = "Guest OS type does not meet condtion `'$GuestOSType`'" + } + Disconnect-VIServer $server -Confirm:$false + return + } + + # Upgrade VMTools and check the tools version status + Write-Host "Upgrading VMTools for VM: $vm..." + $task = Update-Tools -VM $vm -RunAsync + $task | Wait-Task + $task = Get-Task -Id $task.Id + + if ($task.State -eq "Success") { + $upgradeResult = "Completed" + $message = "Upgrade VMTools successfully" + Write-Host "Upgrade VMTools successfully for VM: $vm" -ForegroundColor Green + } else { + $upgradeResult = "Failed" + $message = $task.ExtensionData.Info.Error.LocalizedMessage + Write-Error "Failed to upgrade VMTools for VM: $vm" + } + $vm = Get-VM $vm + # Upgrade result to return + [pscustomobject]@{ + VmName = $vm.Name + UpgradeResult = $upgradeResult + ToolsVersion = $vm.Guest.ToolsVersion + ToolsVersionStatus = $vm.Guest.ExtensionData.ToolsVersionStatus + TotalSeconds = [math]::Floor(($task.FinishTime).Subtract($task.StartTime).TotalSeconds) + Message = $message + } + Write-Verbose “Thread[$ThreadID]: Ending Update-Tools for $vm” + }) | Out-Null + $vc = $Global:DefaultVIServer.ServiceUri.Host + $vcSession = $Global:DefaultVIServer.SessionSecret + $PSThread.AddArgument($vc).AddArgument($vcSession).AddArgument($_.Id).AddArgument($GuestOSType) | Out-Null + + # Start thread + $Handle = $PSThread.BeginInvoke() + $job = New-Object System.Object + $job | Add-Member -type NoteProperty -name Thread -value $PSThread + $job | Add-Member -type NoteProperty -name Handle -value $Handle + $jobs.Add($job) | Out-Null + + Write-Verbose (“Available Runspaces in RunspacePool: {0}” -f $RunspacePool.GetAvailableRunspaces()) + } + } + + End { + #Verify all threads completed + while (($jobs | Where {$_.Handle.iscompleted -ne ‘Completed’}).Count -gt 0) { + Start-Sleep -Seconds 5 + } + + $upgradeResult = $jobs | foreach { + $_.Thread.EndInvoke($_.Handle) + $_.Thread.Dispose() + } + $result += $upgradeResult + $result + + $RunspacePool.Close() + $RunspacePool.Dispose() + } +} + +Export-ModuleMember *-* \ No newline at end of file From 9f2fc3ec065cb451317a2cbb9f9e66691b7fe55e Mon Sep 17 00:00:00 2001 From: William Lam Date: Tue, 14 Nov 2017 06:25:50 -0800 Subject: [PATCH 12/29] Adding several new Content Library functions --- Modules/ContentLibrary/ContentLibrary.psm1 | 386 ++++++++++++++++++++- 1 file changed, 385 insertions(+), 1 deletion(-) diff --git a/Modules/ContentLibrary/ContentLibrary.psm1 b/Modules/ContentLibrary/ContentLibrary.psm1 index 824cb16..da83745 100644 --- a/Modules/ContentLibrary/ContentLibrary.psm1 +++ b/Modules/ContentLibrary/ContentLibrary.psm1 @@ -25,12 +25,29 @@ $results = @() foreach($libraryID in $libaryIDs) { - $library = $contentLibaryService.get($libraryId) + $library = $contentLibaryService.get($libraryID) # Use vCenter REST API to retrieve name of Datastore that is backing the Content Library $datastoreService = Get-CisService com.vmware.vcenter.datastore $datastore = $datastoreService.get($library.storage_backings.datastore_id) + if($library.publish_info.published) { + $published = $library.publish_info.published + $publishedURL = $library.publish_info.publish_url + $externalReplication = $library.publish_info.persist_json_enabled + } else { + $published = $library.publish_info.published + $publishedURL = "N/A" + $externalReplication = "N/A" + } + + if($library.subscription_info) { + $subscribeURL = $library.subscription_info.subscription_url + $published = "N/A" + } else { + $subscribeURL = "N/A" + } + if(!$LibraryName) { $libraryResult = [pscustomobject] @{ Id = $library.Id; @@ -38,6 +55,10 @@ Type = $library.Type; Description = $library.Description; Datastore = $datastore.name; + Published = $published; + PublishedURL = $publishedURL; + JSONPersistence = $externalReplication; + SubscribedURL = $subscribeURL; CreationTime = $library.Creation_Time; } $results+=$libraryResult @@ -49,6 +70,10 @@ Type = $library.Type; Description = $library.Description; Datastore = $datastore.name; + Published = $published; + PublishedURL = $publishedURL; + JSONPersistence = $externalReplication; + SubscribedURL = $subscribeURL; CreationTime = $library.Creation_Time; } $results+=$libraryResult @@ -194,4 +219,363 @@ Function Get-ContentLibraryItemFiles { } } $results +} + +Function Set-ContentLibrary { +<# + .NOTES + =========================================================================== + Created by: William Lam + Organization: VMware + Blog: www.virtuallyghetto.com + Twitter: @lamw + =========================================================================== + .DESCRIPTION + This function updates the JSON Persistence property for a given Content Library + .PARAMETER LibraryName + The name of a vSphere Content Library + .EXAMPLE + Set-ContentLibraryItems -LibraryName Test -JSONPersistenceEnabled + .EXAMPLE + Set-ContentLibraryItems -LibraryName Test -JSONPersistenceDisabled +#> + param( + [Parameter(Mandatory=$true)][String]$LibraryName, + [Parameter(Mandatory=$false)][Switch]$JSONPersistenceEnabled, + [Parameter(Mandatory=$false)][Switch]$JSONPersistenceDisabled + ) + + $contentLibaryService = Get-CisService com.vmware.content.library + $libaryIDs = $contentLibaryService.list() + + $found = $false + foreach($libraryID in $libaryIDs) { + $library = $contentLibaryService.get($libraryId) + if($library.name -eq $LibraryName) { + $found = $true + break + } + } + + if($found) { + $localLibraryService = Get-CisService -Name "com.vmware.content.local_library" + + if($JSONPersistenceEnabled) { + $jsonPersist = $true + } else { + $jsonPersist = $false + } + + $updateSpec = $localLibraryService.Help.update.update_spec.Create() + $updateSpec.type = $library.type + $updateSpec.publish_info.authentication_method = $library.publish_info.authentication_method + $updateSpec.publish_info.persist_json_enabled = $jsonPersist + Write-Host "Updating JSON Persistence configuration setting for $LibraryName ..." + $localLibraryService.update($library.id,$updateSpec) + } else { + Write-Host "Unable to find Content Library $Libraryname" + } +} + +Function New-ExtReplicatedContentLibrary { +<# + .NOTES + =========================================================================== + Created by: William Lam + Organization: VMware + Blog: www.virtuallyghetto.com + Twitter: @lamw + =========================================================================== + .DESCRIPTION + This function creates a new Subscriber Content Library from a JSON Persisted + Content Library that has been externally replicated + .PARAMETER LibraryName + The name of the new vSphere Content Library + .PARAMETER DatastoreName + The name of the vSphere Datastore which contains JSON Persisted configuration file + .PARAMETER SubscribeLibraryName + The name fo the root directroy of the externally replicated Content Library residing on vSphere Datastore + .PARAMETER AutoSync + Whether or not to Automatically sync content + .PARAMETER OnDemand + Only sync content when requested + .EXAMPLE + New-ExtReplicatedContentLibrary -LibraryName Bar -DatastoreName iSCSI-02 -SubscribeLibraryName myExtReplicatedLibrary + .EXAMPLE + New-ExtReplicatedContentLibrary -LibraryName Bar -DatastoreName iSCSI-02 -SubscribeLibraryName myExtReplicatedLibrary -AutoSync $false -OnDemand $true +#> + param( + [Parameter(Mandatory=$true)][String]$LibraryName, + [Parameter(Mandatory=$true)][String]$DatastoreName, + [Parameter(Mandatory=$true)][String]$SubscribeLibraryName, + [Parameter(Mandatory=$false)][Boolean]$AutoSync=$false, + [Parameter(Mandatory=$false)][Boolean]$OnDemand=$true + ) + + $datastore = Get-Datastore -Name $DatastoreName + + if($datastore) { + $datastoreId = $datastore.ExtensionData.MoRef.Value + $datastoreUrl = $datastore.ExtensionData.Info.Url + $subscribeUrl = $datastoreUrl + $SubscribeLibraryName + "/lib.json" + + $subscribeLibraryService = Get-CisService -Name "com.vmware.content.subscribed_library" + + $StorageSpec = [pscustomobject] @{ + datastore_id = $datastoreId; + type = "DATASTORE"; + } + + $UniqueChangeId = [guid]::NewGuid().tostring() + + $createSpec = $subscribeLibraryService.Help.create.create_spec.Create() + $createSpec.name = $LibraryName + $addResults = $createSpec.storage_backings.Add($StorageSpec) + $createSpec.subscription_info.automatic_sync_enabled = $false + $createSpec.subscription_info.on_demand = $true + $createSpec.subscription_info.subscription_url = $subscribeUrl + $createSpec.subscription_info.authentication_method = "NONE" + $createSpec.type = "SUBSCRIBED" + Write-Host "Creating new Externally Replicated Content Library called $LibraryName ..." + $library = $subscribeLibraryService.create($UniqueChangeId,$createSpec) + } +} + +Function Remove-SubscribedContentLibrary { +<# + .NOTES + =========================================================================== + Created by: William Lam + Organization: VMware + Blog: www.virtuallyghetto.com + Twitter: @lamw + =========================================================================== + .DESCRIPTION + This function deletes a Subscriber Content Library + .PARAMETER LibraryName + The name of the new vSphere Content Library to delete + .EXAMPLE + Remove-SubscribedContentLibrary -LibraryName Bar +#> + param( + [Parameter(Mandatory=$true)][String]$LibraryName + ) + + $contentLibaryService = Get-CisService com.vmware.content.library + $libaryIDs = $contentLibaryService.list() + + $found = $false + foreach($libraryID in $libaryIDs) { + $library = $contentLibaryService.get($libraryId) + if($library.name -eq $LibraryName) { + $found = $true + break + } + } + + if($found) { + $subscribeLibraryService = Get-CisService -Name "com.vmware.content.subscribed_library" + + Write-Host "Deleting Subscribed Content Library $LibraryName ..." + $subscribeLibraryService.delete($library.id) + } else { + Write-Host "Unable to find Content Library $LibraryName" + } +} + +Function New-LocalContentLibrary { +<# + .NOTES + =========================================================================== + Created by: William Lam + Organization: VMware + Blog: www.virtuallyghetto.com + Twitter: @lamw + =========================================================================== + .DESCRIPTION + This function creates a new Subscriber Content Library from a JSON Persisted + Content Library that has been externally replicated + .PARAMETER LibraryName + The name of the new vSphere Content Library + .PARAMETER DatastoreName + The name of the vSphere Datastore to store the Content Library + .PARAMETER Publish + Whther or not to publish the Content Library, this is required for JSON Peristence + .PARAMETER JSONPersistence + Whether or not to enable JSON Persistence which enables external replication of Content Library + .EXAMPLE + New-LocalContentLibrary -LibraryName Foo -DatastoreName iSCSI-01 -Publish $true + .EXAMPLE + New-LocalContentLibrary -LibraryName Foo -DatastoreName iSCSI-01 -Publish $true -JSONPersistence $true +#> + param( + [Parameter(Mandatory=$true)][String]$LibraryName, + [Parameter(Mandatory=$true)][String]$DatastoreName, + [Parameter(Mandatory=$false)][Boolean]$Publish=$true, + [Parameter(Mandatory=$false)][Boolean]$JSONPersistence=$false + ) + + $datastore = Get-Datastore -Name $DatastoreName + + if($datastore) { + $datastoreId = $datastore.ExtensionData.MoRef.Value + $localLibraryService = Get-CisService -Name "com.vmware.content.local_library" + + $StorageSpec = [pscustomobject] @{ + datastore_id = $datastoreId; + type = "DATASTORE"; + } + + $UniqueChangeId = [guid]::NewGuid().tostring() + + $createSpec = $localLibraryService.Help.create.create_spec.Create() + $createSpec.name = $LibraryName + $addResults = $createSpec.storage_backings.Add($StorageSpec) + $createSpec.publish_info.authentication_method = "NONE" + $createSpec.publish_info.persist_json_enabled = $JSONPersistence + $createSpec.publish_info.published = $Publish + $createSpec.type = "LOCAL" + Write-Host "Creating new Local Content Library called $LibraryName ..." + $library = $localLibraryService.create($UniqueChangeId,$createSpec) + } +} + +Function Remove-LocalContentLibrary { +<# + .NOTES + =========================================================================== + Created by: William Lam + Organization: VMware + Blog: www.virtuallyghetto.com + Twitter: @lamw + =========================================================================== + .DESCRIPTION + This function deletes a Local Content Library + .PARAMETER LibraryName + The name of the new vSphere Content Library to delete + .EXAMPLE + Remove-LocalContentLibrary -LibraryName Bar +#> + param( + [Parameter(Mandatory=$true)][String]$LibraryName + ) + + $contentLibaryService = Get-CisService com.vmware.content.library + $libaryIDs = $contentLibaryService.list() + + $found = $false + foreach($libraryID in $libaryIDs) { + $library = $contentLibaryService.get($libraryId) + if($library.name -eq $LibraryName) { + $found = $true + break + } + } + + if($found) { + $localLibraryService = Get-CisService -Name "com.vmware.content.local_library" + + Write-Host "Deleting Local Content Library $LibraryName ..." + $localLibraryService.delete($library.id) + } else { + Write-Host "Unable to find Content Library $LibraryName" + } +} + +Function Copy-ContentLibrary { +<# + .NOTES + =========================================================================== + Created by: William Lam + Organization: VMware + Blog: www.virtuallyghetto.com + Twitter: @lamw + =========================================================================== + .DESCRIPTION + This function copies all library items from one Content Library to another + .PARAMETER SourceLibaryName + The name of the source Content Library to copy from + .PARAMETER DestinationLibaryName + The name of the desintation Content Library to copy to + .PARAMETER DeleteSourceFile + Whther or not to delete library item from the source Content Library after copy + .EXAMPLE + Copy-ContentLibrary -SourceLibaryName Foo -DestinationLibaryName Bar + .EXAMPLE + Copy-ContentLibrary -SourceLibaryName Foo -DestinationLibaryName Bar -DeleteSourceFile $true +#> + param( + [Parameter(Mandatory=$true)][String]$SourceLibaryName, + [Parameter(Mandatory=$true)][String]$DestinationLibaryName, + [Parameter(Mandatory=$false)][Boolean]$DeleteSourceFile=$false + ) + + $sourceLibraryId = (Get-ContentLibrary -LibraryName $SourceLibaryName).Id + if($sourceLibraryId -eq $null) { + Write-Host -ForegroundColor red "Unable to find Source Content Library named $SourceLibaryName" + exit + } + $destinationLibraryId = (Get-ContentLibrary -LibraryName $DestinationLibaryName).Id + if($destinationLibraryId -eq $null) { + Write-Host -ForegroundColor Red "Unable to find Destination Content Library named $DestinationLibaryName" + break + } + + $sourceItemFiles = Get-ContentLibraryItems -LibraryName $SourceLibaryName + if($sourceItemFiles -eq $null) { + Write-Host -ForegroundColor red "Unable to retrieve Content Library Items from $SourceLibaryName" + break + } + + $contentLibaryItemService = Get-CisService com.vmware.content.library.item + + foreach ($sourceItemFile in $sourceItemFiles) { + # Check to see if file already exists in destination Content Library + $result = Get-ContentLibraryItems -LibraryName $DestinationLibaryName -LibraryItemName $sourceItemFile.Name + + if($result -eq $null) { + # Create CopySpec + $copySpec = $contentLibaryItemService.Help.copy.destination_create_spec.Create() + $copySpec.library_id = $destinationLibraryId + $copySpec.name = $sourceItemFile.Name + $copySpec.description = $sourceItemFile.Description + # Create random Unique Copy Id + $UniqueChangeId = [guid]::NewGuid().tostring() + + # Perform Copy + try { + Write-Host -ForegroundColor Cyan "Copying" $sourceItemFile.Name "..." + $copyResult = $contentLibaryItemService.copy($UniqueChangeId, $sourceItemFile.Id, $copySpec) + } catch { + Write-Host -ForegroundColor Red "Failed to copy" $sourceItemFile.Name + $Error[0] + break + } + + # Delete source file if set to true + if($DeleteSourceFile) { + try { + Write-Host -ForegroundColor Magenta "Deleteing" $sourceItemFile.Name "..." + #$deleteResult = $contentLibaryItemService.delete($sourceItemFile.Id) + } catch { + Write-Host -ForegroundColor Red "Failed to delete" $sourceItemFile.Name + $Error[0] + break + } + } + } else { + Write-Host -ForegroundColor Yellow "Skipping" $sourceItemFile.Name "already exists" + + # Delete source file if set to true + if($DeleteSourceFile) { + try { + Write-Host -ForegroundColor Magenta "Deleteing" $sourceItemFile.Name "..." + #$deleteResult = $contentLibaryItemService.delete($sourceItemFile.Id) + } catch { + Write-Host -ForegroundColor Red "Failed to delete" $sourceItemFile.Name + break + } + } + } + } } \ No newline at end of file From 2d429c62717c4fac6590625738ce6e2bf9cd7a4e Mon Sep 17 00:00:00 2001 From: William Lam Date: Tue, 14 Nov 2017 06:45:58 -0800 Subject: [PATCH 13/29] Forgot to un-comment the delete code --- Modules/ContentLibrary/ContentLibrary.psm1 | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Modules/ContentLibrary/ContentLibrary.psm1 b/Modules/ContentLibrary/ContentLibrary.psm1 index da83745..e2fef41 100644 --- a/Modules/ContentLibrary/ContentLibrary.psm1 +++ b/Modules/ContentLibrary/ContentLibrary.psm1 @@ -556,7 +556,7 @@ Function Copy-ContentLibrary { if($DeleteSourceFile) { try { Write-Host -ForegroundColor Magenta "Deleteing" $sourceItemFile.Name "..." - #$deleteResult = $contentLibaryItemService.delete($sourceItemFile.Id) + $deleteResult = $contentLibaryItemService.delete($sourceItemFile.Id) } catch { Write-Host -ForegroundColor Red "Failed to delete" $sourceItemFile.Name $Error[0] @@ -570,7 +570,7 @@ Function Copy-ContentLibrary { if($DeleteSourceFile) { try { Write-Host -ForegroundColor Magenta "Deleteing" $sourceItemFile.Name "..." - #$deleteResult = $contentLibaryItemService.delete($sourceItemFile.Id) + $deleteResult = $contentLibaryItemService.delete($sourceItemFile.Id) } catch { Write-Host -ForegroundColor Red "Failed to delete" $sourceItemFile.Name break From a47369a29572e0b0458a3d81e1c31621688c1b56 Mon Sep 17 00:00:00 2001 From: Chris Date: Mon, 20 Nov 2017 15:22:21 +0000 Subject: [PATCH 14/29] Minor Spelling corrections generted->generated Minor Spelling corrections generted->generated in Get-Help examples --- Modules/VMware.VMEncryption/VMware.VMEncryption.psm1 | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Modules/VMware.VMEncryption/VMware.VMEncryption.psm1 b/Modules/VMware.VMEncryption/VMware.VMEncryption.psm1 index e91b0c5..023087c 100644 --- a/Modules/VMware.VMEncryption/VMware.VMEncryption.psm1 +++ b/Modules/VMware.VMEncryption/VMware.VMEncryption.psm1 @@ -882,7 +882,7 @@ Function Set-VMEncryptionKey { C:\PS>$VM|Set-VMEncryptionKey -KMSClusterId $KMSCluster.Id -Deep Deep rekeys the VM Home and all its disks using a new key. - The key is generted from the KMS whose clusterId is $KMSCluster.Id. + The key is generated from the KMS whose clusterId is $KMSCluster.Id. .NOTES This cmdlet assumes there is already a KMS in vCenter Server. If VM is not encrypted, the cmdlet quits. @@ -1037,7 +1037,7 @@ Function Set-VMDiskEncryptionKey { C:\PS>$HardDisk| Set-VMDiskEncryptionKey -VM $VM -KMSClusterId $KMSCluster.Id -Deep Deep rekeys all the disks of the $VM using a new key. - The key is generted from the KMS whose clusterId is $KMSCluster.Id. + The key is generated from the KMS whose clusterId is $KMSCluster.Id. .NOTES This cmdlet assumes there is already a KMS in vCenter Server. From dc6b02a95ae5f1f3ee7d53d6f7747682190e5345 Mon Sep 17 00:00:00 2001 From: William Lam Date: Tue, 21 Nov 2017 07:39:22 -0800 Subject: [PATCH 15/29] Export/Import functions for manual vCenter Server Migrations --- Modules/vCenterManualMigration.psm1 | 475 ++++++++++++++++++++++++++++ 1 file changed, 475 insertions(+) create mode 100644 Modules/vCenterManualMigration.psm1 diff --git a/Modules/vCenterManualMigration.psm1 b/Modules/vCenterManualMigration.psm1 new file mode 100644 index 0000000..a7750b9 --- /dev/null +++ b/Modules/vCenterManualMigration.psm1 @@ -0,0 +1,475 @@ +Function Export-DRSRules { +<# + .NOTES + =========================================================================== + Created by: William Lam + Date: 11/21/2017 + Blog: https://www.virtuallyghetto.com + Twitter: @lamw + =========================================================================== + + .SYNOPSIS + Export DRS Rules to JSON file based on VMworld Demo https://youtu.be/MagjfbIL4kg + .DESCRIPTION + Export DRS Rules to JSON file based on VMworld Demo https://youtu.be/MagjfbIL4kg + .EXAMPLE + Export-DRSRules -Path C:\Users\primp\Desktop\VMworld2017 -Cluster Windows-Cluster +#> + param( + [Parameter(Mandatory=$false)][String]$Path, + [Parameter(Mandatory=$true)][String]$Cluster + ) + + $rules = Get-Cluster -Name $Cluster | Get-DrsRule + + $results = @() + foreach ($rule in $rules) { + $vmNames = @() + $vmIds = $rule.VMIds + + # Reconstruct MoRef ID to VM Object to get Name + foreach ($vmId in $vmIds) { + $vm = New-Object VMware.Vim.ManagedObjectReference + $vm.Type = "VirtualMachine" + $vm.Value = ($vmId -replace "VirtualMachine-","") + $vmView = Get-View $vm + $vmNames += $vmView.name + } + + $rulesObject = [pscustomobject] @{ + Name = $rule.ExtensionData.Name; + Type = $rule.Type; #VMAffinity = 1, VMAntiAffinity = 0 + Enabled = $rule.Enabled; + Mandatory = $rule.ExtensionData.Mandatory + VM = $vmNames + } + $results+=$rulesObject + } + if($Path) { + $fullPath = $Path + "\DRSRules.json" + Write-Host -ForegroundColor Green "Exporting DRS Rules to $fullpath ..." + $results | ConvertTo-Json | Out-File $fullPath + } else { + $results | ConvertTo-Json + } +} + +Function Import-DRSRules { +<# + .NOTES + =========================================================================== + Created by: William Lam + Date: 11/21/2017 + Blog: https://www.virtuallyghetto.com + Twitter: @lamw + =========================================================================== + + .SYNOPSIS + Import DRS Rules from JSON file based on VMworld Demo https://youtu.be/MagjfbIL4kg + .DESCRIPTION + Import DRS Rules from JSON file based on VMworld Demo https://youtu.be/MagjfbIL4kg + .EXAMPLE + Import-DRSRules -Path C:\Users\primp\Desktop\VMworld2017 -Cluster Windows-Cluster +#> + param( + [Parameter(Mandatory=$true)][String]$Path, + [Parameter(Mandatory=$true)][String]$Cluster + ) + + Get-DrsRule -Cluster $cluster | Remove-DrsRule -Confirm:$false | Out-Null + + $DRSRulesFilename = "/DRSRules.json" + $fullPath = $Path + $DRSRulesFilename + $json = Get-Content -Raw $fullPath | ConvertFrom-Json + + foreach ($line in $json) { + $vmArr = @() + $vmNames = $line.vm + foreach ($vmName in $vmNames) { + $vmView = Get-VM -Name $vmName + $vmArr+=$vmView + } + New-DrsRule -Name $line.name -Enabled $line.Enabled -Cluster (Get-Cluster -Name $Cluster) -KeepTogether $line.Type -VM $vmArr + } +} + +Function Export-DRSClusterGroup { +<# + .NOTES + =========================================================================== + Created by: William Lam + Date: 11/21/2017 + Blog: https://www.virtuallyghetto.com + Twitter: @lamw + =========================================================================== + + .SYNOPSIS + Export DRS Cluster Group Rules to JSON file based on VMworld Demo https://youtu.be/MagjfbIL4kg + .DESCRIPTION + Export DRS Cluster Group Rules to JSON file based on VMworld Demo https://youtu.be/MagjfbIL4kg + .EXAMPLE + Export-DRSClusterGroup -Path C:\Users\primp\Desktop\VMworld2017 -Cluster Windows-Cluster +#> + param( + [Parameter(Mandatory=$false)][String]$Path, + [Parameter(Mandatory=$true)][String]$Cluster + ) + + $rules = Get-Cluster -Name $Cluster | Get-DrsClusterGroup + + $results = @() + foreach ($rule in $rules) { + $rulesObject = [pscustomobject] @{ + Name = $rule.ExtensionData.Name; + Type = $rule.GroupType; #VMType = 1, HostType = 0 + Member = $rule.Member + } + $results+=$rulesObject + } + if($Path) { + $fullPath = $Path + "\DRSClusterGroupRules.json" + Write-Host -ForegroundColor Green "Exporting DRS Cluster Group Rules to $fullpath ..." + $results | ConvertTo-Json | Out-File $fullPath + } else { + $results | ConvertTo-Json + } +} + +Function Import-DRSClusterClusterGroup { +<# + .NOTES + =========================================================================== + Created by: William Lam + Date: 11/21/2017 + Blog: https://www.virtuallyghetto.com + Twitter: @lamw + =========================================================================== + + .SYNOPSIS + Import DRS Cluster Group Rules from JSON file based on VMworld Demo https://youtu.be/MagjfbIL4kg + .DESCRIPTION + Import DRS Cluster Group Rules from JSON file based on VMworld Demo https://youtu.be/MagjfbIL4kg + .EXAMPLE + Import-DRSClusterClusterGroup -Path C:\Users\primp\Desktop\VMworld2017 -Cluster Windows-Cluster +#> + param( + [Parameter(Mandatory=$true)][String]$Path, + [Parameter(Mandatory=$true)][String]$Cluster + ) + + $DRSClusterGroupRulesFilename = "\DRSClusterGroupRules.json" + $fullPath = $Path + $DRSClusterGroupRulesFilename + $json = Get-Content -Raw $fullPath | ConvertFrom-Json + + foreach ($line in $json) { + $memberArr = @() + $members = $line.member + + # VMHost Group + if($line.Type -eq 0) { + foreach ($member in $members) { + $memberView = Get-VMhost -Name $member + $memberArr+=$memberView + } + New-DrsClusterGroup -Name $line.name -Cluster (Get-Cluster -Name $Cluster) -VMhost $memberArr + # VM Group + } else { + foreach ($member in $members) { + $memberView = Get-VM -Name $member + $memberArr+=$memberView + } + New-DrsClusterGroup -Name $line.name -Cluster (Get-Cluster -Name $Cluster) -VM $memberArr + } + } +} + +Function Export-Tag { +<# + .NOTES + =========================================================================== + Created by: William Lam + Date: 11/21/2017 + Blog: https://www.virtuallyghetto.com + Twitter: @lamw + =========================================================================== + + .SYNOPSIS + Export vSphere Tags and VM Assocations to JSON file based on VMworld Demo https://youtu.be/MagjfbIL4kg + .DESCRIPTION + Export vSphere Tags and VM Assocations to JSON file based on VMworld Demo https://youtu.be/MagjfbIL4kg + .EXAMPLE + Export-Tag -Path C:\Users\primp\Desktop\VMworld2017 +#> + param( + [Parameter(Mandatory=$false)][String]$Path + ) + + # Export Tag Categories + $tagCatagorys = Get-TagCategory + + $tagCatresults = @() + foreach ($tagCategory in $tagCatagorys) { + $tagCatObj = [pscustomobject] @{ + Name = $tagCategory.Name; + Cardinality = $tagCategory.Cardinality; + Description = $tagCategory.Description; + Type = $tagCategory.EntityType + } + $tagCatresults+=$tagCatObj + } + if($Path) { + $fullPath = $Path + "\AllTagCategory.json" + Write-Host -ForegroundColor Green "Exporting vSphere Tag Category to $fullpath ..." + $tagCatresults | ConvertTo-Json | Out-File $fullPath + } else { + $tagCatresults | ConvertTo-Json + } + + # Export Tags + $tags = Get-Tag + + $tagResults = @() + foreach ($tag in $tags) { + $tagObj = [pscustomobject] @{ + Name = $tag.Name; + Description = $tag.Description; + Category = $tag.Category.Name + } + $tagResults+=$tagObj + } + if($Path) { + $fullPath = $Path + "\AllTag.json" + Write-Host -ForegroundColor Green "Exporting vSphere Tag to $fullpath ..." + $tagResults | ConvertTo-Json | Out-File $fullPath + } else { + $tagResults | ConvertTo-Json + } + + # Export VM to Tag Mappings + $vms = Get-VM + + $vmResults = @() + foreach ($vm in $vms) { + $tagAssignments = $vm | Get-TagAssignment + $tags = @() + foreach ($tagAssignment in $tagAssignments) { + $tag = $tagAssignment.Tag + $tagName = $tag -split "/" + $tags+=$tagName + } + $vmObj = [pscustomobject] @{ + Name = $vm.name; + Tag = $tags + } + $vmResults+=$vmObj + } + if($Path) { + $fullPath = $Path + "\AllTagAssocations.json" + Write-Host -ForegroundColor Green "Exporting VM to vSphere Tag Assignment to $fullpath ..." + $vmResults | ConvertTo-Json | Out-File $fullPath + } else { + $vmResults | ConvertTo-Json + } +} + +Function Import-Tag { +<# + .NOTES + =========================================================================== + Created by: William Lam + Date: 11/21/2017 + Blog: https://www.virtuallyghetto.com + Twitter: @lamw + =========================================================================== + + .SYNOPSIS + Import vSphere Tags and VM Assocations from JSON file based on VMworld Demo https://youtu.be/MagjfbIL4kg + .DESCRIPTION + Import vSphere Tags and VM Assocations from JSON file based on VMworld Demo https://youtu.be/MagjfbIL4kg + .EXAMPLE + Import-Tag -Path C:\Users\primp\Desktop\VMworld2017 +#> + param( + [Parameter(Mandatory=$true)][String]$Path + ) + + $tagCatFilename = "\AllTagCategory.json" + $fullPath = $Path + $tagCatFilename + $tagCategoryJson = Get-Content -Raw $fullPath | ConvertFrom-Json + + $tagFilename = "\AllTag.json" + $fullPath = $Path + $tagFilename + $tagJson = Get-Content -Raw $fullPath | ConvertFrom-Json + + $vmTagFilename = "\AllTagAssocations.json" + $fullPath = $Path + $vmTagFilename + $vmTagJson = Get-Content -Raw $fullPath | ConvertFrom-Json + + # Re-Create Tag Category + foreach ($category in $tagCategoryJson) { + if($category.Cardinality -eq 0) { + $cardinality = "Single" + } else { + $cardinality = "Multiple" + } + New-TagCategory -Name $category.Name -Cardinality $cardinality -Description $category.Description -EntityType $category.Type + } + + # Re-Create Tags + foreach ($tag in $tagJson) { + New-Tag -Name $tag.Name -Description $tag.Description -Category (Get-TagCategory -Name $tag.Category) + } + + # Re-Create VM to Tag Mappings + foreach ($vmTag in $vmTagJson) { + $vm = Get-VM -Name $vmTag.name + $tags = $vmTag.Tag + foreach ($tag in $tags) { + New-TagAssignment -Entity $vm -Tag (Get-Tag -Name $tag) + } + } +} + +Function Export-VMFolder { +<# + .NOTES + =========================================================================== + Created by: William Lam + Date: 11/21/2017 + Blog: https://www.virtuallyghetto.com + Twitter: @lamw + =========================================================================== + + .SYNOPSIS + Export vSphere Folder to JSON file based on VMworld Demo https://youtu.be/MagjfbIL4kg + .DESCRIPTION + Export vSphere Folder to JSON file based on VMworld Demo https://youtu.be/MagjfbIL4kg + .EXAMPLE + Export-VMFolder -Path C:\Users\primp\Desktop\VMworld2017 +#> + param( + [Parameter(Mandatory=$false)][String]$Path + ) + $vms = Get-VM + + $vmFolderResults = @() + foreach ($vm in $vms) { + $vmFolderObj = [pscustomobject] @{ + Name = $vm.name; + Folder = $vm.Folder.Name; + } + $vmFolderResults+=$vmFolderObj + } + if($Path) { + $fullPath = $Path + "\AllVMFolder.json" + Write-Host -ForegroundColor Green "Exporting VM Folders to $fullpath ..." + $vmFolderResults | ConvertTo-Json | Out-File $fullPath + } else { + $vmFolderResults | ConvertTo-Json + } +} + +Function Import-VMFolder { +<# + .NOTES + =========================================================================== + Created by: William Lam + Date: 11/21/2017 + Blog: https://www.virtuallyghetto.com + Twitter: @lamw + =========================================================================== + + .SYNOPSIS + Import vSphere Folder from JSON file based on VMworld Demo https://youtu.be/MagjfbIL4kg + .DESCRIPTION + Import vSphere Folder from JSON file based on VMworld Demo https://youtu.be/MagjfbIL4kg + .EXAMPLE + Import-VMFolder -Path C:\Users\primp\Desktop\VMworld2017 +#> + param( + [Parameter(Mandatory=$true)][String]$Path + ) + + $vmFolderFilename = "\AllVMFolder.json" + $fullPath = $Path + $vmFolderFilename + $vmFolderJson = Get-Content -Raw $fullPath | ConvertFrom-Json + + # Root vm Folder + $rootVMFolder = Get-Folder -Type VM -Name vm + + $folders = $vmFolderJson | Select Folder | Sort-Object -Property Folder -Unique + foreach ($folder in $folders) { + $rootVMFolder | New-Folder -Name $folder.folder + } + + foreach ($vmFolder in $vmFolderJson) { + $vm = Get-VM -Name $vmFolder.Name + $folder = Get-Folder -Name $vmFolder.Folder + Move-VM -VM $vm -Destination $folder + } +} + +Function Export-VMStoragePolicy { +<# + .NOTES + =========================================================================== + Created by: William Lam + Date: 11/21/2017 + Blog: https://www.virtuallyghetto.com + Twitter: @lamw + =========================================================================== + + .SYNOPSIS + Export VM Storage Policies to JSON file + .DESCRIPTION + Export VM Storage Policies to JSON file + .EXAMPLE + Export-VMStoragePolicy -Path C:\Users\primp\Desktop\VMworld2017 +#> + param( + [Parameter(Mandatory=$false)][String]$Path + ) + + foreach ($policy in Get-SpbmStoragePolicy) { + $policyName = $policy.Name + if($Path) { + Write-Host -ForegroundColor Green "Exporting Policy $policyName to $Path\$policyName.xml ..." + $policy | Export-SpbmStoragePolicy -FilePath $Path\$policyName.xml -Force | Out-Null + } else { + $policy + } + } +} + +Function Import-VMStoragePolicy { +<# + .NOTES + =========================================================================== + Created by: William Lam + Date: 11/21/2017 + Blog: https://www.virtuallyghetto.com + Twitter: @lamw + =========================================================================== + + .SYNOPSIS + Import VM Storage Policies from JSON file + .DESCRIPTION + Import VM Storage Policies from JSON file + .EXAMPLE + Import-VMStoragePolicy -Path C:\Users\primp\Desktop\VMworld2017 +#> + param( + [Parameter(Mandatory=$false)][String]$Path + ) + + foreach ($file in Get-ChildItem -Path $Path -Filter *.xml) { + $policyName = $file.name + $policyName = $policyName.replace(".xml","") + if(Get-SpbmStoragePolicy -Name $policyName -ErrorAction SilentlyContinue) { + Continue + } else { + Write-Host "Importing Policy $policyname ..." + Import-SpbmStoragePolicy -FilePath $Path\$file -Name $policyName + } + } +} \ No newline at end of file From cdfd510dd9cfb7e61f3cf23f7fc13e3fbfd55585 Mon Sep 17 00:00:00 2001 From: William Lam Date: Tue, 21 Nov 2017 09:37:27 -0800 Subject: [PATCH 16/29] Whoops, missed folder for module --- Modules/vCenterManualMigration.psm1 | 475 ---------------------------- 1 file changed, 475 deletions(-) delete mode 100644 Modules/vCenterManualMigration.psm1 diff --git a/Modules/vCenterManualMigration.psm1 b/Modules/vCenterManualMigration.psm1 deleted file mode 100644 index a7750b9..0000000 --- a/Modules/vCenterManualMigration.psm1 +++ /dev/null @@ -1,475 +0,0 @@ -Function Export-DRSRules { -<# - .NOTES - =========================================================================== - Created by: William Lam - Date: 11/21/2017 - Blog: https://www.virtuallyghetto.com - Twitter: @lamw - =========================================================================== - - .SYNOPSIS - Export DRS Rules to JSON file based on VMworld Demo https://youtu.be/MagjfbIL4kg - .DESCRIPTION - Export DRS Rules to JSON file based on VMworld Demo https://youtu.be/MagjfbIL4kg - .EXAMPLE - Export-DRSRules -Path C:\Users\primp\Desktop\VMworld2017 -Cluster Windows-Cluster -#> - param( - [Parameter(Mandatory=$false)][String]$Path, - [Parameter(Mandatory=$true)][String]$Cluster - ) - - $rules = Get-Cluster -Name $Cluster | Get-DrsRule - - $results = @() - foreach ($rule in $rules) { - $vmNames = @() - $vmIds = $rule.VMIds - - # Reconstruct MoRef ID to VM Object to get Name - foreach ($vmId in $vmIds) { - $vm = New-Object VMware.Vim.ManagedObjectReference - $vm.Type = "VirtualMachine" - $vm.Value = ($vmId -replace "VirtualMachine-","") - $vmView = Get-View $vm - $vmNames += $vmView.name - } - - $rulesObject = [pscustomobject] @{ - Name = $rule.ExtensionData.Name; - Type = $rule.Type; #VMAffinity = 1, VMAntiAffinity = 0 - Enabled = $rule.Enabled; - Mandatory = $rule.ExtensionData.Mandatory - VM = $vmNames - } - $results+=$rulesObject - } - if($Path) { - $fullPath = $Path + "\DRSRules.json" - Write-Host -ForegroundColor Green "Exporting DRS Rules to $fullpath ..." - $results | ConvertTo-Json | Out-File $fullPath - } else { - $results | ConvertTo-Json - } -} - -Function Import-DRSRules { -<# - .NOTES - =========================================================================== - Created by: William Lam - Date: 11/21/2017 - Blog: https://www.virtuallyghetto.com - Twitter: @lamw - =========================================================================== - - .SYNOPSIS - Import DRS Rules from JSON file based on VMworld Demo https://youtu.be/MagjfbIL4kg - .DESCRIPTION - Import DRS Rules from JSON file based on VMworld Demo https://youtu.be/MagjfbIL4kg - .EXAMPLE - Import-DRSRules -Path C:\Users\primp\Desktop\VMworld2017 -Cluster Windows-Cluster -#> - param( - [Parameter(Mandatory=$true)][String]$Path, - [Parameter(Mandatory=$true)][String]$Cluster - ) - - Get-DrsRule -Cluster $cluster | Remove-DrsRule -Confirm:$false | Out-Null - - $DRSRulesFilename = "/DRSRules.json" - $fullPath = $Path + $DRSRulesFilename - $json = Get-Content -Raw $fullPath | ConvertFrom-Json - - foreach ($line in $json) { - $vmArr = @() - $vmNames = $line.vm - foreach ($vmName in $vmNames) { - $vmView = Get-VM -Name $vmName - $vmArr+=$vmView - } - New-DrsRule -Name $line.name -Enabled $line.Enabled -Cluster (Get-Cluster -Name $Cluster) -KeepTogether $line.Type -VM $vmArr - } -} - -Function Export-DRSClusterGroup { -<# - .NOTES - =========================================================================== - Created by: William Lam - Date: 11/21/2017 - Blog: https://www.virtuallyghetto.com - Twitter: @lamw - =========================================================================== - - .SYNOPSIS - Export DRS Cluster Group Rules to JSON file based on VMworld Demo https://youtu.be/MagjfbIL4kg - .DESCRIPTION - Export DRS Cluster Group Rules to JSON file based on VMworld Demo https://youtu.be/MagjfbIL4kg - .EXAMPLE - Export-DRSClusterGroup -Path C:\Users\primp\Desktop\VMworld2017 -Cluster Windows-Cluster -#> - param( - [Parameter(Mandatory=$false)][String]$Path, - [Parameter(Mandatory=$true)][String]$Cluster - ) - - $rules = Get-Cluster -Name $Cluster | Get-DrsClusterGroup - - $results = @() - foreach ($rule in $rules) { - $rulesObject = [pscustomobject] @{ - Name = $rule.ExtensionData.Name; - Type = $rule.GroupType; #VMType = 1, HostType = 0 - Member = $rule.Member - } - $results+=$rulesObject - } - if($Path) { - $fullPath = $Path + "\DRSClusterGroupRules.json" - Write-Host -ForegroundColor Green "Exporting DRS Cluster Group Rules to $fullpath ..." - $results | ConvertTo-Json | Out-File $fullPath - } else { - $results | ConvertTo-Json - } -} - -Function Import-DRSClusterClusterGroup { -<# - .NOTES - =========================================================================== - Created by: William Lam - Date: 11/21/2017 - Blog: https://www.virtuallyghetto.com - Twitter: @lamw - =========================================================================== - - .SYNOPSIS - Import DRS Cluster Group Rules from JSON file based on VMworld Demo https://youtu.be/MagjfbIL4kg - .DESCRIPTION - Import DRS Cluster Group Rules from JSON file based on VMworld Demo https://youtu.be/MagjfbIL4kg - .EXAMPLE - Import-DRSClusterClusterGroup -Path C:\Users\primp\Desktop\VMworld2017 -Cluster Windows-Cluster -#> - param( - [Parameter(Mandatory=$true)][String]$Path, - [Parameter(Mandatory=$true)][String]$Cluster - ) - - $DRSClusterGroupRulesFilename = "\DRSClusterGroupRules.json" - $fullPath = $Path + $DRSClusterGroupRulesFilename - $json = Get-Content -Raw $fullPath | ConvertFrom-Json - - foreach ($line in $json) { - $memberArr = @() - $members = $line.member - - # VMHost Group - if($line.Type -eq 0) { - foreach ($member in $members) { - $memberView = Get-VMhost -Name $member - $memberArr+=$memberView - } - New-DrsClusterGroup -Name $line.name -Cluster (Get-Cluster -Name $Cluster) -VMhost $memberArr - # VM Group - } else { - foreach ($member in $members) { - $memberView = Get-VM -Name $member - $memberArr+=$memberView - } - New-DrsClusterGroup -Name $line.name -Cluster (Get-Cluster -Name $Cluster) -VM $memberArr - } - } -} - -Function Export-Tag { -<# - .NOTES - =========================================================================== - Created by: William Lam - Date: 11/21/2017 - Blog: https://www.virtuallyghetto.com - Twitter: @lamw - =========================================================================== - - .SYNOPSIS - Export vSphere Tags and VM Assocations to JSON file based on VMworld Demo https://youtu.be/MagjfbIL4kg - .DESCRIPTION - Export vSphere Tags and VM Assocations to JSON file based on VMworld Demo https://youtu.be/MagjfbIL4kg - .EXAMPLE - Export-Tag -Path C:\Users\primp\Desktop\VMworld2017 -#> - param( - [Parameter(Mandatory=$false)][String]$Path - ) - - # Export Tag Categories - $tagCatagorys = Get-TagCategory - - $tagCatresults = @() - foreach ($tagCategory in $tagCatagorys) { - $tagCatObj = [pscustomobject] @{ - Name = $tagCategory.Name; - Cardinality = $tagCategory.Cardinality; - Description = $tagCategory.Description; - Type = $tagCategory.EntityType - } - $tagCatresults+=$tagCatObj - } - if($Path) { - $fullPath = $Path + "\AllTagCategory.json" - Write-Host -ForegroundColor Green "Exporting vSphere Tag Category to $fullpath ..." - $tagCatresults | ConvertTo-Json | Out-File $fullPath - } else { - $tagCatresults | ConvertTo-Json - } - - # Export Tags - $tags = Get-Tag - - $tagResults = @() - foreach ($tag in $tags) { - $tagObj = [pscustomobject] @{ - Name = $tag.Name; - Description = $tag.Description; - Category = $tag.Category.Name - } - $tagResults+=$tagObj - } - if($Path) { - $fullPath = $Path + "\AllTag.json" - Write-Host -ForegroundColor Green "Exporting vSphere Tag to $fullpath ..." - $tagResults | ConvertTo-Json | Out-File $fullPath - } else { - $tagResults | ConvertTo-Json - } - - # Export VM to Tag Mappings - $vms = Get-VM - - $vmResults = @() - foreach ($vm in $vms) { - $tagAssignments = $vm | Get-TagAssignment - $tags = @() - foreach ($tagAssignment in $tagAssignments) { - $tag = $tagAssignment.Tag - $tagName = $tag -split "/" - $tags+=$tagName - } - $vmObj = [pscustomobject] @{ - Name = $vm.name; - Tag = $tags - } - $vmResults+=$vmObj - } - if($Path) { - $fullPath = $Path + "\AllTagAssocations.json" - Write-Host -ForegroundColor Green "Exporting VM to vSphere Tag Assignment to $fullpath ..." - $vmResults | ConvertTo-Json | Out-File $fullPath - } else { - $vmResults | ConvertTo-Json - } -} - -Function Import-Tag { -<# - .NOTES - =========================================================================== - Created by: William Lam - Date: 11/21/2017 - Blog: https://www.virtuallyghetto.com - Twitter: @lamw - =========================================================================== - - .SYNOPSIS - Import vSphere Tags and VM Assocations from JSON file based on VMworld Demo https://youtu.be/MagjfbIL4kg - .DESCRIPTION - Import vSphere Tags and VM Assocations from JSON file based on VMworld Demo https://youtu.be/MagjfbIL4kg - .EXAMPLE - Import-Tag -Path C:\Users\primp\Desktop\VMworld2017 -#> - param( - [Parameter(Mandatory=$true)][String]$Path - ) - - $tagCatFilename = "\AllTagCategory.json" - $fullPath = $Path + $tagCatFilename - $tagCategoryJson = Get-Content -Raw $fullPath | ConvertFrom-Json - - $tagFilename = "\AllTag.json" - $fullPath = $Path + $tagFilename - $tagJson = Get-Content -Raw $fullPath | ConvertFrom-Json - - $vmTagFilename = "\AllTagAssocations.json" - $fullPath = $Path + $vmTagFilename - $vmTagJson = Get-Content -Raw $fullPath | ConvertFrom-Json - - # Re-Create Tag Category - foreach ($category in $tagCategoryJson) { - if($category.Cardinality -eq 0) { - $cardinality = "Single" - } else { - $cardinality = "Multiple" - } - New-TagCategory -Name $category.Name -Cardinality $cardinality -Description $category.Description -EntityType $category.Type - } - - # Re-Create Tags - foreach ($tag in $tagJson) { - New-Tag -Name $tag.Name -Description $tag.Description -Category (Get-TagCategory -Name $tag.Category) - } - - # Re-Create VM to Tag Mappings - foreach ($vmTag in $vmTagJson) { - $vm = Get-VM -Name $vmTag.name - $tags = $vmTag.Tag - foreach ($tag in $tags) { - New-TagAssignment -Entity $vm -Tag (Get-Tag -Name $tag) - } - } -} - -Function Export-VMFolder { -<# - .NOTES - =========================================================================== - Created by: William Lam - Date: 11/21/2017 - Blog: https://www.virtuallyghetto.com - Twitter: @lamw - =========================================================================== - - .SYNOPSIS - Export vSphere Folder to JSON file based on VMworld Demo https://youtu.be/MagjfbIL4kg - .DESCRIPTION - Export vSphere Folder to JSON file based on VMworld Demo https://youtu.be/MagjfbIL4kg - .EXAMPLE - Export-VMFolder -Path C:\Users\primp\Desktop\VMworld2017 -#> - param( - [Parameter(Mandatory=$false)][String]$Path - ) - $vms = Get-VM - - $vmFolderResults = @() - foreach ($vm in $vms) { - $vmFolderObj = [pscustomobject] @{ - Name = $vm.name; - Folder = $vm.Folder.Name; - } - $vmFolderResults+=$vmFolderObj - } - if($Path) { - $fullPath = $Path + "\AllVMFolder.json" - Write-Host -ForegroundColor Green "Exporting VM Folders to $fullpath ..." - $vmFolderResults | ConvertTo-Json | Out-File $fullPath - } else { - $vmFolderResults | ConvertTo-Json - } -} - -Function Import-VMFolder { -<# - .NOTES - =========================================================================== - Created by: William Lam - Date: 11/21/2017 - Blog: https://www.virtuallyghetto.com - Twitter: @lamw - =========================================================================== - - .SYNOPSIS - Import vSphere Folder from JSON file based on VMworld Demo https://youtu.be/MagjfbIL4kg - .DESCRIPTION - Import vSphere Folder from JSON file based on VMworld Demo https://youtu.be/MagjfbIL4kg - .EXAMPLE - Import-VMFolder -Path C:\Users\primp\Desktop\VMworld2017 -#> - param( - [Parameter(Mandatory=$true)][String]$Path - ) - - $vmFolderFilename = "\AllVMFolder.json" - $fullPath = $Path + $vmFolderFilename - $vmFolderJson = Get-Content -Raw $fullPath | ConvertFrom-Json - - # Root vm Folder - $rootVMFolder = Get-Folder -Type VM -Name vm - - $folders = $vmFolderJson | Select Folder | Sort-Object -Property Folder -Unique - foreach ($folder in $folders) { - $rootVMFolder | New-Folder -Name $folder.folder - } - - foreach ($vmFolder in $vmFolderJson) { - $vm = Get-VM -Name $vmFolder.Name - $folder = Get-Folder -Name $vmFolder.Folder - Move-VM -VM $vm -Destination $folder - } -} - -Function Export-VMStoragePolicy { -<# - .NOTES - =========================================================================== - Created by: William Lam - Date: 11/21/2017 - Blog: https://www.virtuallyghetto.com - Twitter: @lamw - =========================================================================== - - .SYNOPSIS - Export VM Storage Policies to JSON file - .DESCRIPTION - Export VM Storage Policies to JSON file - .EXAMPLE - Export-VMStoragePolicy -Path C:\Users\primp\Desktop\VMworld2017 -#> - param( - [Parameter(Mandatory=$false)][String]$Path - ) - - foreach ($policy in Get-SpbmStoragePolicy) { - $policyName = $policy.Name - if($Path) { - Write-Host -ForegroundColor Green "Exporting Policy $policyName to $Path\$policyName.xml ..." - $policy | Export-SpbmStoragePolicy -FilePath $Path\$policyName.xml -Force | Out-Null - } else { - $policy - } - } -} - -Function Import-VMStoragePolicy { -<# - .NOTES - =========================================================================== - Created by: William Lam - Date: 11/21/2017 - Blog: https://www.virtuallyghetto.com - Twitter: @lamw - =========================================================================== - - .SYNOPSIS - Import VM Storage Policies from JSON file - .DESCRIPTION - Import VM Storage Policies from JSON file - .EXAMPLE - Import-VMStoragePolicy -Path C:\Users\primp\Desktop\VMworld2017 -#> - param( - [Parameter(Mandatory=$false)][String]$Path - ) - - foreach ($file in Get-ChildItem -Path $Path -Filter *.xml) { - $policyName = $file.name - $policyName = $policyName.replace(".xml","") - if(Get-SpbmStoragePolicy -Name $policyName -ErrorAction SilentlyContinue) { - Continue - } else { - Write-Host "Importing Policy $policyname ..." - Import-SpbmStoragePolicy -FilePath $Path\$file -Name $policyName - } - } -} \ No newline at end of file From d104a293934819d792ce2ab1af449c5af51ce236 Mon Sep 17 00:00:00 2001 From: William Lam Date: Tue, 21 Nov 2017 09:38:24 -0800 Subject: [PATCH 17/29] Might be useful if I actually added directory --- .../vCenterManualMigration.psm1 | 475 ++++++++++++++++++ 1 file changed, 475 insertions(+) create mode 100644 Modules/vCenterManualMigration/vCenterManualMigration.psm1 diff --git a/Modules/vCenterManualMigration/vCenterManualMigration.psm1 b/Modules/vCenterManualMigration/vCenterManualMigration.psm1 new file mode 100644 index 0000000..a7750b9 --- /dev/null +++ b/Modules/vCenterManualMigration/vCenterManualMigration.psm1 @@ -0,0 +1,475 @@ +Function Export-DRSRules { +<# + .NOTES + =========================================================================== + Created by: William Lam + Date: 11/21/2017 + Blog: https://www.virtuallyghetto.com + Twitter: @lamw + =========================================================================== + + .SYNOPSIS + Export DRS Rules to JSON file based on VMworld Demo https://youtu.be/MagjfbIL4kg + .DESCRIPTION + Export DRS Rules to JSON file based on VMworld Demo https://youtu.be/MagjfbIL4kg + .EXAMPLE + Export-DRSRules -Path C:\Users\primp\Desktop\VMworld2017 -Cluster Windows-Cluster +#> + param( + [Parameter(Mandatory=$false)][String]$Path, + [Parameter(Mandatory=$true)][String]$Cluster + ) + + $rules = Get-Cluster -Name $Cluster | Get-DrsRule + + $results = @() + foreach ($rule in $rules) { + $vmNames = @() + $vmIds = $rule.VMIds + + # Reconstruct MoRef ID to VM Object to get Name + foreach ($vmId in $vmIds) { + $vm = New-Object VMware.Vim.ManagedObjectReference + $vm.Type = "VirtualMachine" + $vm.Value = ($vmId -replace "VirtualMachine-","") + $vmView = Get-View $vm + $vmNames += $vmView.name + } + + $rulesObject = [pscustomobject] @{ + Name = $rule.ExtensionData.Name; + Type = $rule.Type; #VMAffinity = 1, VMAntiAffinity = 0 + Enabled = $rule.Enabled; + Mandatory = $rule.ExtensionData.Mandatory + VM = $vmNames + } + $results+=$rulesObject + } + if($Path) { + $fullPath = $Path + "\DRSRules.json" + Write-Host -ForegroundColor Green "Exporting DRS Rules to $fullpath ..." + $results | ConvertTo-Json | Out-File $fullPath + } else { + $results | ConvertTo-Json + } +} + +Function Import-DRSRules { +<# + .NOTES + =========================================================================== + Created by: William Lam + Date: 11/21/2017 + Blog: https://www.virtuallyghetto.com + Twitter: @lamw + =========================================================================== + + .SYNOPSIS + Import DRS Rules from JSON file based on VMworld Demo https://youtu.be/MagjfbIL4kg + .DESCRIPTION + Import DRS Rules from JSON file based on VMworld Demo https://youtu.be/MagjfbIL4kg + .EXAMPLE + Import-DRSRules -Path C:\Users\primp\Desktop\VMworld2017 -Cluster Windows-Cluster +#> + param( + [Parameter(Mandatory=$true)][String]$Path, + [Parameter(Mandatory=$true)][String]$Cluster + ) + + Get-DrsRule -Cluster $cluster | Remove-DrsRule -Confirm:$false | Out-Null + + $DRSRulesFilename = "/DRSRules.json" + $fullPath = $Path + $DRSRulesFilename + $json = Get-Content -Raw $fullPath | ConvertFrom-Json + + foreach ($line in $json) { + $vmArr = @() + $vmNames = $line.vm + foreach ($vmName in $vmNames) { + $vmView = Get-VM -Name $vmName + $vmArr+=$vmView + } + New-DrsRule -Name $line.name -Enabled $line.Enabled -Cluster (Get-Cluster -Name $Cluster) -KeepTogether $line.Type -VM $vmArr + } +} + +Function Export-DRSClusterGroup { +<# + .NOTES + =========================================================================== + Created by: William Lam + Date: 11/21/2017 + Blog: https://www.virtuallyghetto.com + Twitter: @lamw + =========================================================================== + + .SYNOPSIS + Export DRS Cluster Group Rules to JSON file based on VMworld Demo https://youtu.be/MagjfbIL4kg + .DESCRIPTION + Export DRS Cluster Group Rules to JSON file based on VMworld Demo https://youtu.be/MagjfbIL4kg + .EXAMPLE + Export-DRSClusterGroup -Path C:\Users\primp\Desktop\VMworld2017 -Cluster Windows-Cluster +#> + param( + [Parameter(Mandatory=$false)][String]$Path, + [Parameter(Mandatory=$true)][String]$Cluster + ) + + $rules = Get-Cluster -Name $Cluster | Get-DrsClusterGroup + + $results = @() + foreach ($rule in $rules) { + $rulesObject = [pscustomobject] @{ + Name = $rule.ExtensionData.Name; + Type = $rule.GroupType; #VMType = 1, HostType = 0 + Member = $rule.Member + } + $results+=$rulesObject + } + if($Path) { + $fullPath = $Path + "\DRSClusterGroupRules.json" + Write-Host -ForegroundColor Green "Exporting DRS Cluster Group Rules to $fullpath ..." + $results | ConvertTo-Json | Out-File $fullPath + } else { + $results | ConvertTo-Json + } +} + +Function Import-DRSClusterClusterGroup { +<# + .NOTES + =========================================================================== + Created by: William Lam + Date: 11/21/2017 + Blog: https://www.virtuallyghetto.com + Twitter: @lamw + =========================================================================== + + .SYNOPSIS + Import DRS Cluster Group Rules from JSON file based on VMworld Demo https://youtu.be/MagjfbIL4kg + .DESCRIPTION + Import DRS Cluster Group Rules from JSON file based on VMworld Demo https://youtu.be/MagjfbIL4kg + .EXAMPLE + Import-DRSClusterClusterGroup -Path C:\Users\primp\Desktop\VMworld2017 -Cluster Windows-Cluster +#> + param( + [Parameter(Mandatory=$true)][String]$Path, + [Parameter(Mandatory=$true)][String]$Cluster + ) + + $DRSClusterGroupRulesFilename = "\DRSClusterGroupRules.json" + $fullPath = $Path + $DRSClusterGroupRulesFilename + $json = Get-Content -Raw $fullPath | ConvertFrom-Json + + foreach ($line in $json) { + $memberArr = @() + $members = $line.member + + # VMHost Group + if($line.Type -eq 0) { + foreach ($member in $members) { + $memberView = Get-VMhost -Name $member + $memberArr+=$memberView + } + New-DrsClusterGroup -Name $line.name -Cluster (Get-Cluster -Name $Cluster) -VMhost $memberArr + # VM Group + } else { + foreach ($member in $members) { + $memberView = Get-VM -Name $member + $memberArr+=$memberView + } + New-DrsClusterGroup -Name $line.name -Cluster (Get-Cluster -Name $Cluster) -VM $memberArr + } + } +} + +Function Export-Tag { +<# + .NOTES + =========================================================================== + Created by: William Lam + Date: 11/21/2017 + Blog: https://www.virtuallyghetto.com + Twitter: @lamw + =========================================================================== + + .SYNOPSIS + Export vSphere Tags and VM Assocations to JSON file based on VMworld Demo https://youtu.be/MagjfbIL4kg + .DESCRIPTION + Export vSphere Tags and VM Assocations to JSON file based on VMworld Demo https://youtu.be/MagjfbIL4kg + .EXAMPLE + Export-Tag -Path C:\Users\primp\Desktop\VMworld2017 +#> + param( + [Parameter(Mandatory=$false)][String]$Path + ) + + # Export Tag Categories + $tagCatagorys = Get-TagCategory + + $tagCatresults = @() + foreach ($tagCategory in $tagCatagorys) { + $tagCatObj = [pscustomobject] @{ + Name = $tagCategory.Name; + Cardinality = $tagCategory.Cardinality; + Description = $tagCategory.Description; + Type = $tagCategory.EntityType + } + $tagCatresults+=$tagCatObj + } + if($Path) { + $fullPath = $Path + "\AllTagCategory.json" + Write-Host -ForegroundColor Green "Exporting vSphere Tag Category to $fullpath ..." + $tagCatresults | ConvertTo-Json | Out-File $fullPath + } else { + $tagCatresults | ConvertTo-Json + } + + # Export Tags + $tags = Get-Tag + + $tagResults = @() + foreach ($tag in $tags) { + $tagObj = [pscustomobject] @{ + Name = $tag.Name; + Description = $tag.Description; + Category = $tag.Category.Name + } + $tagResults+=$tagObj + } + if($Path) { + $fullPath = $Path + "\AllTag.json" + Write-Host -ForegroundColor Green "Exporting vSphere Tag to $fullpath ..." + $tagResults | ConvertTo-Json | Out-File $fullPath + } else { + $tagResults | ConvertTo-Json + } + + # Export VM to Tag Mappings + $vms = Get-VM + + $vmResults = @() + foreach ($vm in $vms) { + $tagAssignments = $vm | Get-TagAssignment + $tags = @() + foreach ($tagAssignment in $tagAssignments) { + $tag = $tagAssignment.Tag + $tagName = $tag -split "/" + $tags+=$tagName + } + $vmObj = [pscustomobject] @{ + Name = $vm.name; + Tag = $tags + } + $vmResults+=$vmObj + } + if($Path) { + $fullPath = $Path + "\AllTagAssocations.json" + Write-Host -ForegroundColor Green "Exporting VM to vSphere Tag Assignment to $fullpath ..." + $vmResults | ConvertTo-Json | Out-File $fullPath + } else { + $vmResults | ConvertTo-Json + } +} + +Function Import-Tag { +<# + .NOTES + =========================================================================== + Created by: William Lam + Date: 11/21/2017 + Blog: https://www.virtuallyghetto.com + Twitter: @lamw + =========================================================================== + + .SYNOPSIS + Import vSphere Tags and VM Assocations from JSON file based on VMworld Demo https://youtu.be/MagjfbIL4kg + .DESCRIPTION + Import vSphere Tags and VM Assocations from JSON file based on VMworld Demo https://youtu.be/MagjfbIL4kg + .EXAMPLE + Import-Tag -Path C:\Users\primp\Desktop\VMworld2017 +#> + param( + [Parameter(Mandatory=$true)][String]$Path + ) + + $tagCatFilename = "\AllTagCategory.json" + $fullPath = $Path + $tagCatFilename + $tagCategoryJson = Get-Content -Raw $fullPath | ConvertFrom-Json + + $tagFilename = "\AllTag.json" + $fullPath = $Path + $tagFilename + $tagJson = Get-Content -Raw $fullPath | ConvertFrom-Json + + $vmTagFilename = "\AllTagAssocations.json" + $fullPath = $Path + $vmTagFilename + $vmTagJson = Get-Content -Raw $fullPath | ConvertFrom-Json + + # Re-Create Tag Category + foreach ($category in $tagCategoryJson) { + if($category.Cardinality -eq 0) { + $cardinality = "Single" + } else { + $cardinality = "Multiple" + } + New-TagCategory -Name $category.Name -Cardinality $cardinality -Description $category.Description -EntityType $category.Type + } + + # Re-Create Tags + foreach ($tag in $tagJson) { + New-Tag -Name $tag.Name -Description $tag.Description -Category (Get-TagCategory -Name $tag.Category) + } + + # Re-Create VM to Tag Mappings + foreach ($vmTag in $vmTagJson) { + $vm = Get-VM -Name $vmTag.name + $tags = $vmTag.Tag + foreach ($tag in $tags) { + New-TagAssignment -Entity $vm -Tag (Get-Tag -Name $tag) + } + } +} + +Function Export-VMFolder { +<# + .NOTES + =========================================================================== + Created by: William Lam + Date: 11/21/2017 + Blog: https://www.virtuallyghetto.com + Twitter: @lamw + =========================================================================== + + .SYNOPSIS + Export vSphere Folder to JSON file based on VMworld Demo https://youtu.be/MagjfbIL4kg + .DESCRIPTION + Export vSphere Folder to JSON file based on VMworld Demo https://youtu.be/MagjfbIL4kg + .EXAMPLE + Export-VMFolder -Path C:\Users\primp\Desktop\VMworld2017 +#> + param( + [Parameter(Mandatory=$false)][String]$Path + ) + $vms = Get-VM + + $vmFolderResults = @() + foreach ($vm in $vms) { + $vmFolderObj = [pscustomobject] @{ + Name = $vm.name; + Folder = $vm.Folder.Name; + } + $vmFolderResults+=$vmFolderObj + } + if($Path) { + $fullPath = $Path + "\AllVMFolder.json" + Write-Host -ForegroundColor Green "Exporting VM Folders to $fullpath ..." + $vmFolderResults | ConvertTo-Json | Out-File $fullPath + } else { + $vmFolderResults | ConvertTo-Json + } +} + +Function Import-VMFolder { +<# + .NOTES + =========================================================================== + Created by: William Lam + Date: 11/21/2017 + Blog: https://www.virtuallyghetto.com + Twitter: @lamw + =========================================================================== + + .SYNOPSIS + Import vSphere Folder from JSON file based on VMworld Demo https://youtu.be/MagjfbIL4kg + .DESCRIPTION + Import vSphere Folder from JSON file based on VMworld Demo https://youtu.be/MagjfbIL4kg + .EXAMPLE + Import-VMFolder -Path C:\Users\primp\Desktop\VMworld2017 +#> + param( + [Parameter(Mandatory=$true)][String]$Path + ) + + $vmFolderFilename = "\AllVMFolder.json" + $fullPath = $Path + $vmFolderFilename + $vmFolderJson = Get-Content -Raw $fullPath | ConvertFrom-Json + + # Root vm Folder + $rootVMFolder = Get-Folder -Type VM -Name vm + + $folders = $vmFolderJson | Select Folder | Sort-Object -Property Folder -Unique + foreach ($folder in $folders) { + $rootVMFolder | New-Folder -Name $folder.folder + } + + foreach ($vmFolder in $vmFolderJson) { + $vm = Get-VM -Name $vmFolder.Name + $folder = Get-Folder -Name $vmFolder.Folder + Move-VM -VM $vm -Destination $folder + } +} + +Function Export-VMStoragePolicy { +<# + .NOTES + =========================================================================== + Created by: William Lam + Date: 11/21/2017 + Blog: https://www.virtuallyghetto.com + Twitter: @lamw + =========================================================================== + + .SYNOPSIS + Export VM Storage Policies to JSON file + .DESCRIPTION + Export VM Storage Policies to JSON file + .EXAMPLE + Export-VMStoragePolicy -Path C:\Users\primp\Desktop\VMworld2017 +#> + param( + [Parameter(Mandatory=$false)][String]$Path + ) + + foreach ($policy in Get-SpbmStoragePolicy) { + $policyName = $policy.Name + if($Path) { + Write-Host -ForegroundColor Green "Exporting Policy $policyName to $Path\$policyName.xml ..." + $policy | Export-SpbmStoragePolicy -FilePath $Path\$policyName.xml -Force | Out-Null + } else { + $policy + } + } +} + +Function Import-VMStoragePolicy { +<# + .NOTES + =========================================================================== + Created by: William Lam + Date: 11/21/2017 + Blog: https://www.virtuallyghetto.com + Twitter: @lamw + =========================================================================== + + .SYNOPSIS + Import VM Storage Policies from JSON file + .DESCRIPTION + Import VM Storage Policies from JSON file + .EXAMPLE + Import-VMStoragePolicy -Path C:\Users\primp\Desktop\VMworld2017 +#> + param( + [Parameter(Mandatory=$false)][String]$Path + ) + + foreach ($file in Get-ChildItem -Path $Path -Filter *.xml) { + $policyName = $file.name + $policyName = $policyName.replace(".xml","") + if(Get-SpbmStoragePolicy -Name $policyName -ErrorAction SilentlyContinue) { + Continue + } else { + Write-Host "Importing Policy $policyname ..." + Import-SpbmStoragePolicy -FilePath $Path\$file -Name $policyName + } + } +} \ No newline at end of file From d6861d38fb4e8eac4d2168220d0e5f8047e62f4b Mon Sep 17 00:00:00 2001 From: alanrenouf Date: Tue, 28 Nov 2017 22:48:08 -0800 Subject: [PATCH 18/29] New VMware Cloud on AWS functions module --- Modules/VMware.VMC/VMware.VMC.psd1 | Bin 0 -> 7976 bytes Modules/VMware.VMC/VMware.VMC.psm1 | 323 +++++++++++++++++++++++++++++ 2 files changed, 323 insertions(+) create mode 100755 Modules/VMware.VMC/VMware.VMC.psd1 create mode 100644 Modules/VMware.VMC/VMware.VMC.psm1 diff --git a/Modules/VMware.VMC/VMware.VMC.psd1 b/Modules/VMware.VMC/VMware.VMC.psd1 new file mode 100755 index 0000000000000000000000000000000000000000..74256ef01bb8a2e4a146aa91e45b35b01949b08f GIT binary patch literal 7976 zcmeI1T~Av_5Qg`fUvVTZOsa;IG)tQXdha$WT=b;}i!f6=j?kse}C=A1~?xta;C&zj} ziEqkut#GK7m!h7Cax>m_LM!q#zR&c0q`!%1X8P`n$5Hqce$h8;M&f%R?%nVte9*p$ zS5I%wmT)@PdN^(Ab1&QvkMw^l{5)T^CZ2!k+K}vro^~9Dag^sQlhKI$#ki^S@>P+_&*dyU5lGS@~I{Plr^7ZUJK8{+hANxzQ?lNPg?U>QvN6&cXj_zDDUg)fi(SCobL)d*N=477gaw# zhh`wkhjB&HPFuLx-Tde}3#^5l))2KN6A@R)KT=F2{z;#sD5>r9A=36&+BN6!O1qtD zwdp_iynNTO_9JReBprExY+zo`dbFQ%!y^5&ca@LHy&*l`5r_M-1aVtb@<}0Wo$5ob za12BinFIfrC}-d$o2BU3j_*>edz2)rAop?fsGjiK`>uAukMXRr_@0Zid6;LcJhIFF zwP;6^aZkK1Bi4QC5bs5vaug;FzKmYbmA1)5C!#Co*CKSZmV5~&i~V+ZrzlJ|dl^>_ zWnFSY5%n{Xu9~&*E>hz`m!c^YqfJ<`vmrur=$<$n#;fJpY2w+OcOF!7PV&;+cB`Q# z8m)HS6!H23O+24-Ot{R#UswBIPmX3Q+*BGoj%Y*M*olm=8D6O}9O!CCZ!Fhb>g^=F zzp)2xYQ@1-O(iyod-p*+n|ee&z=J<%HzFCo^qz&h1Vxi47OFPnlK0|5mMU~tu4oo# zR2*t2p0O>undBSje_gsSqfa(W6m|{lh>}|S-$(K zXm_F?GqDmW{{`YQf>lvhxN-E%Zm8S1gK6C)sX*&sGa2jSyYF2id0B>if0&LLlWHOJd5DW{X?y?Nz9^y&8t-uhZPGERgz zjhcy<^)IG<&RkBHtl!g0t1&&vv$ud6?RZDujMnkwT}bMWJFFYY} zVD(&w&05c`zOB5}k&Vd(bo%u4*7x78qWCN~6&HHhoaZWtUdRiq4p|LG@>3x!*I@jE zQ_!B~OPkrKHO*(msjeHga&=96)oW~em*XgRLbt`R6D#IGGo{N~-=BVR80T)QmVHUe z8KK*Sy_wGZ-m7U@PhYxM$){O*18OlA!p?>4!8`;?>xV$g`SiA)7L8vlm2t-rU5>KFP>a~ z99Km~hNd64y22?AxrUsQ=AWjM3fI4XV~54O@T}In())_fdd8}!@)>fs?UzSgJy*~x zELvI4mMONId9d^IDEnBQ>?qDU=G(hhSei9&HKe+hs97vPq6y@_L>X&;*kfQEDf&+@;RHii7+~obbEIu5kES*xhV$Ej0Py W|Bjy+sms{OWGU0<+WD;2YvEtFqc#)( literal 0 HcmV?d00001 diff --git a/Modules/VMware.VMC/VMware.VMC.psm1 b/Modules/VMware.VMC/VMware.VMC.psm1 new file mode 100644 index 0000000..674668b --- /dev/null +++ b/Modules/VMware.VMC/VMware.VMC.psm1 @@ -0,0 +1,323 @@ +Function Get-VMCCommand { +<# + .NOTES + =========================================================================== + Created by: VMware + Date: 11/17/2017 + Organization: VMware + Blog: http://vmware.com/go/powercli + Twitter: @powercli + =========================================================================== + + .SYNOPSIS + Returns all cmdlets for VMware Cloud on AWS + .DESCRIPTION + This cmdlet will allow you to return all cmdlets included in the VMC module + .EXAMPLE + Get-VMCCommand + .EXAMPLE + Get-Command -Module VMware.VMC + .NOTES + You can either use this cmdlet or the Get-Command cmdlet as seen in Example 2 +#> + Get-command -Module VMware.VimAutomation.Vmc + Get-Command -Module VMware.VMC + +} +Function Connect-VMCVIServer { +<# + .NOTES + =========================================================================== + Created by: VMware + Date: 11/17/2017 + Organization: VMware + Blog: http://vmware.com/go/powercli + Twitter: @powercli + =========================================================================== + + .SYNOPSIS + Cmdlet to connect to your VMC vCenter Server + .DESCRIPTION + This will connect you to both the VMC ViServer as well as the CiSServer at the same time. + .EXAMPLE + Connect-VMCVIServer -Server -User -Password + .NOTES + Easiest way is to pipe through your credentials from Get-VMCSDDCDefaultCredential +#> + Param ( + [Parameter(Mandatory=$true)]$Org, + [Parameter(Mandatory=$true)]$Sddc, + [switch]$Autologin + ) + + If (-Not $global:DefaultVMCServers) { Write-error "No VMC Connection found, please use the Connect-VMC to connect" } Else { + $creds = Get-VMCSDDCDefaultCredential -Org $Org -Sddc $Sddc + Write-Host "Connecting to VMC vCenter Server" $creds.vc_public_ip + Connect-VIServer -Server $creds.vc_public_ip -User $creds.cloud_username -Password $creds.cloud_password | Add-Member -MemberType Noteproperty -Name Location -Value "VMC" + Write-Host "Connecting to VMC CIS Endpoint" $creds.vc_public_ip + Connect-CisServer -Server $creds.vc_public_ip -User $creds.cloud_username -Password $creds.cloud_password | Add-Member -MemberType Noteproperty -Name Location -Value "VMC" + } +} +Function Get-VMCOrg { +<# + .NOTES + =========================================================================== + Created by: VMware + Date: 11/17/2017 + Organization: VMware + Blog: http://vmware.com/go/powercli + Twitter: @powercli + =========================================================================== + + .SYNOPSIS + Return the Orgs that you are a part of + .DESCRIPTION + Depending on what you've purchased, you may be a part of one or more VMC Orgs. This will return your orgs + .EXAMPLE + Get-VMCOrg + .EXAMPLE + Get-VMCOrg -Name + .NOTES + Return all the info about the orgs you are a part of +#> + Param ( + [Parameter(Mandatory=$false)]$Name + ) + + If (-Not $global:DefaultVMCServers) { Write-error "No VMC Connection found, please use Connect-VMC to connect" } Else { + $orgService = Get-VMCService com.vmware.vmc.orgs + if ($PSBoundParameters.ContainsKey("Name")){ + $orgs = $orgService.list() | Where {$_.display_name -match $Name} + } Else { + $orgs = $orgService.list() + } + $Orgs | Select display_name, name, user_name, created, id + } +} +Function Get-VMCSDDC { +<# + .NOTES + =========================================================================== + Created by: VMware + Date: 11/17/2017 + Organization: VMware + Blog: http://vmware.com/go/powercli + Twitter: @powercli + =========================================================================== + + .SYNOPSIS + Returns all of the SDDCs you are associated to + .DESCRIPTION + Returns all of the SDDCs ayou are associated to + .EXAMPLE + Get-VMCSDDC -Org + .EXAMPLE + Get-VMCSDDC -Name -Org +#> + Param ( + [Parameter(Mandatory=$True)]$Org, + [Parameter(Mandatory=$false)]$Name + ) + + If (-Not $global:DefaultVMCServers) { Write-error "No VMC Connection found, please use the Connect-VMC to connect" } Else { + if ($PSBoundParameters.ContainsKey("Org")){ + $orgs = Get-VMCOrg -Name $Org + } else { + $orgs = Get-VMCOrg + } + + foreach ($org in $orgs) { + $orgID = $org.ID + $sddcService = Get-VMCService com.vmware.vmc.orgs.sddcs + if ($PSBoundParameters.ContainsKey("Name")){ + $sddcService.list($OrgID) | Where {$_.name -match $Name} + } Else { + $sddcService.list($OrgID) + } + } + } +} +Function Get-VMCTask { +<# + .NOTES + =========================================================================== + Created by: VMware + Date: 11/17/2017 + Organization: VMware + Blog: http://vmware.com/go/powercli + Twitter: @powercli + =========================================================================== + + .SYNOPSIS + Returns all of the VMC Tasks + .DESCRIPTION + Returns all of the VMC Tasks that have either occurred or are in process + .EXAMPLE + Get-VMCTask +#> + Param ( + [Parameter(Mandatory=$True)]$Org + ) + + If (-Not $global:DefaultVMCServers) { Write-error "No VMC Connection found, please use the Connect-VMC to connect" } Else { + if ($PSBoundParameters.ContainsKey("Org")){ + $orgs = Get-VMCOrg -Name $Org + } else { + $orgs = Get-VMCOrg + } + + foreach ($org in $orgs) { + $orgID = $org.ID + $taskService = Get-VMCService com.vmware.vmc.orgs.tasks + $taskService.list($OrgID) | Select * -ExcludeProperty Help + } + } +} +Function Get-VMCSDDCDefaultCredential { +<# + .NOTES + =========================================================================== + Created by: VMware + Date: 11/17/2017 + Organization: VMware + Blog: http://vmware.com/go/powercli + Twitter: @powercli + =========================================================================== + + .SYNOPSIS + Returns the default credential for the SDDC + .DESCRIPTION + Returns the default credential for the sddc + .EXAMPLE + Get-VMCSDDCDefaultCredential -Org + .EXAMPLE + Get-VMCSDDCDefaultCredential -Sddc -Org +#> + Param ( + [Parameter(Mandatory=$true)]$Org, + [Parameter(Mandatory=$false)]$Sddc + ) + + If (-Not $global:DefaultVMCServers) { Write-error "No VMC Connection found, please use the Connect-VMC to connect" } Else { + if ($PSBoundParameters.ContainsKey("Sddc")){ + $sddcs = Get-VMCSDDC -Name $Sddc -Org $Org + } else { + $sddcs = Get-VMCSDDC -Org $Org + } + + foreach ($sddc in $sddcs) { + $sddc.resource_config | Select-object vc_url, vc_management_ip, vc_public_ip, cloud_username, cloud_password + } + } +} +Function Get-VMCSDDCPublicIP { +<# + .NOTES + =========================================================================== + Created by: VMware + Date: 11/17/2017 + Organization: VMware + Blog: http://vmware.com/go/powercli + Twitter: @powercli + =========================================================================== + + .SYNOPSIS + Returns your Public IPs + .DESCRIPTION + Returns your Public IPs + .EXAMPLE + Get-VMCSDDCPublicIP -Org + .EXAMPLE + Get-VMCSDDCPublicIP -Sddc -Org + .NOTES + Return your Public IPs that you have assigned to your account +#> + Param ( + [Parameter(Mandatory=$true)]$Org, + [Parameter(Mandatory=$false)]$Sddc + ) + + If (-Not $global:DefaultVMCServers) { Write-error "No VMC Connection found, please use the Connect-VMC to connect" } Else { + if ($PSBoundParameters.ContainsKey("Sddc")){ + $sddcs = Get-VMCSDDC -Name $Sddc -Org $Org + } else { + $sddcs = Get-VMCSDDC -Org $Org + } + + foreach ($sddc in $sddcs) { + $sddc.resource_config.Public_ip_pool + } + } +} +Function Get-VMCVMHost { + Param ( + [Parameter(Mandatory=$false)]$Sddc, + [Parameter(Mandatory=$true)]$Org + ) + + If (-Not $global:DefaultVMCServers) { Write-error "No VMC Connection found, please use the Connect-VMC to connect" } Else { + if ($PSBoundParameters.ContainsKey("Sddc")){ + $sddcs = Get-VMCSDDC -Name $Sddc -Org $Org + } else { + $sddcs = Get-VMCSDDC -Org $Org + } + + $results = @() + foreach ($sddc in $sddcs) { + foreach ($vmhost in $sddc.resource_config.esx_hosts) { + $tmp = [pscustomobject] @{ + esx_id = $vmhost.esx_id; + name = $vmhost.name; + hostname = $vmhost.hostname; + esx_state = $vmhost.esx_state; + sddc_id = $sddc.id; + org_id = $sddc.org_id; + } + $results += $tmp + } + $results + } + } +} +Function Get-VMCSDDCVersion { +<# + .NOTES + =========================================================================== + Created by: VMware + Date: 11/17/2017 + Organization: VMware + Blog: http://vmware.com/go/powercli + Twitter: @powercli + =========================================================================== + + .SYNOPSIS + Returns SDDC Version + .DESCRIPTION + Returns Version of the SDDC + .EXAMPLE + Get-VMCSDDCVersion -Name -Org +#> + Param ( + [Parameter(Mandatory=$True)]$Org, + [Parameter(Mandatory=$false)]$Name + ) + + If (-Not $global:DefaultVMCServers) { Write-error "No VMC Connection found, please use the Connect-VMC to connect" } Else { + if ($PSBoundParameters.ContainsKey("Org")){ + $orgs = Get-VMCOrg -Name $Org + } else { + $orgs = Get-VMCOrg + } + + foreach ($org in $orgs) { + $orgID = $org.ID + $sddcService = Get-VMCService com.vmware.vmc.orgs.sddcs + if ($PSBoundParameters.ContainsKey("Name")){ + ($sddcService.list($OrgID) | Where {$_.name -match $Name}).resource_config.sddc_manifest | Select *version + } Else { + ($sddcService.list($OrgID)).resource_config.sddc_manifest | Select *version + } + } + } +} +Export-ModuleMember -Function 'Get-VMCCommand', 'Connect-VMCVIServer', 'Get-VMCOrg', 'Get-VMCSDDC', 'Get-VMCTask', 'Get-VMCSDDCDefaultCredential', 'Get-VMCSDDCPublicIP', 'Get-VMCVMHost', 'Get-VMCSDDCVersion' \ No newline at end of file From 2c2b16457cf5dcb47e99821f6a10f8bb5fec5ffc Mon Sep 17 00:00:00 2001 From: lucdekens Date: Fri, 1 Dec 2017 23:08:04 +0100 Subject: [PATCH 19/29] Add module rCisTag Module rCisTag provides CRUD functions for Tags, Tag Categories and Tag Assignments. The functions use the Cis REST API functions. This is a beta release (0.9.0), feedback welcome. --- Modules/rCisTag/MITLicense.txt | 21 + Modules/rCisTag/README.md | 15 + Modules/rCisTag/en-US/about_rCISTag.Help.txt | 26 + Modules/rCisTag/en-US/rCISTag-help.xml | 1793 ++++++++++++++++++ Modules/rCisTag/rCISTag.psd1 | Bin 0 -> 5838 bytes Modules/rCisTag/rCISTag.psm1 | 821 ++++++++ 6 files changed, 2676 insertions(+) create mode 100644 Modules/rCisTag/MITLicense.txt create mode 100644 Modules/rCisTag/README.md create mode 100644 Modules/rCisTag/en-US/about_rCISTag.Help.txt create mode 100644 Modules/rCisTag/en-US/rCISTag-help.xml create mode 100644 Modules/rCisTag/rCISTag.psd1 create mode 100644 Modules/rCisTag/rCISTag.psm1 diff --git a/Modules/rCisTag/MITLicense.txt b/Modules/rCisTag/MITLicense.txt new file mode 100644 index 0000000..b4eaf48 --- /dev/null +++ b/Modules/rCisTag/MITLicense.txt @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) since 2015 Luc Dekens, Matt Boren + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. \ No newline at end of file diff --git a/Modules/rCisTag/README.md b/Modules/rCisTag/README.md new file mode 100644 index 0000000..4160fdc --- /dev/null +++ b/Modules/rCisTag/README.md @@ -0,0 +1,15 @@ +# rCisTag + +A module with cmdlets to provide CRUD functions to +* Tags +* Tag Categories +* Tag Assignments + +The cmdlets use the Cis REST API + +## History + +* Author : **Luc Dekens** +* Release : + * **0.9.0** First draft + \ No newline at end of file diff --git a/Modules/rCisTag/en-US/about_rCISTag.Help.txt b/Modules/rCisTag/en-US/about_rCISTag.Help.txt new file mode 100644 index 0000000..f3b393f --- /dev/null +++ b/Modules/rCisTag/en-US/about_rCISTag.Help.txt @@ -0,0 +1,26 @@ +TOPIC + about_rCISTag + +SHORT DESCRIPTION + The rCisTag module provides CRUD functions to work with vSphere Tags + +LONG DESCRIPTION + The CisTag module provides CRUD functions to work with vSphere Tags. + The functions in the module are based on the REST API + +NOTE + The module requires PowerShell 5.0 + +TROUBLESHOOTING NOTE + + + +EXAMPLES + Get-rCisTag + +KEYWORDS + + + +SEE ALSO + Place related topics here. \ No newline at end of file diff --git a/Modules/rCisTag/en-US/rCISTag-help.xml b/Modules/rCisTag/en-US/rCISTag-help.xml new file mode 100644 index 0000000..023f48c --- /dev/null +++ b/Modules/rCisTag/en-US/rCISTag-help.xml @@ -0,0 +1,1793 @@ + + + + + Connect-rCisServer + Connect + rCisServer + + Make a connection to the CIS service on the vCenter + + + + Make a connection to the CIS service on the vCenter. Credentials need to be provided. + + + + Connect-rCisServer + + Confirm + + Prompts you for confirmation before running the cmdlet. + + + SwitchParameter + + + False + + + Credential + + A PSCredential object with a user and password that is allowed to connect to the CIS service. + + PSCredential + + PSCredential + + + None + + + Fiddler + + Connects to a Fiddler instance on the station where the cmdlet is executed. Used for debugging purposes. + + + SwitchParameter + + + False + + + Proxy + + When the vCenter is located behind a proxy, specify the proxy. + + String + + String + + + None + + + Server + + The hostname of the vCenter + + String + + String + + + None + + + WhatIf + + Shows what would happen if the cmdlet runs. The cmdlet is not run. + + + SwitchParameter + + + False + + + + Connect-rCisServer + + Confirm + + Prompts you for confirmation before running the cmdlet. + + + SwitchParameter + + + False + + + Fiddler + + Connects to a Fiddler instance on the station where the cmdlet is executed. Used for debugging purposes. + + + SwitchParameter + + + False + + + Password + + The user's password + + String + + String + + + None + + + Proxy + + When the vCenter is located behind a proxy, specify the proxy. + + String + + String + + + None + + + Server + + The hostname of the vCenter + + String + + String + + + None + + + User + + The user to connect to the CIS service + + String + + String + + + None + + + WhatIf + + Shows what would happen if the cmdlet runs. The cmdlet is not run. + + + SwitchParameter + + + False + + + + + + Confirm + + Prompts you for confirmation before running the cmdlet. + + SwitchParameter + + SwitchParameter + + + False + + + Credential + + A PSCredential object with a user and password that is allowed to connect to the CIS service. + + PSCredential + + PSCredential + + + None + + + Fiddler + + Connects to a Fiddler instance on the station where the cmdlet is executed. Used for debugging purposes. + + SwitchParameter + + SwitchParameter + + + False + + + Password + + The user's password + + String + + String + + + None + + + Proxy + + When the vCenter is located behind a proxy, specify the proxy. + + String + + String + + + None + + + Server + + The hostname of the vCenter + + String + + String + + + None + + + User + + The user to connect to the CIS service + + String + + String + + + None + + + WhatIf + + Shows what would happen if the cmdlet runs. The cmdlet is not run. + + SwitchParameter + + SwitchParameter + + + False + + + + + + System.Management.Automation.PSCredential + + + + + + + + + + System.Object + + + + + + + + + + + + + + Example 1 + PS C:\> Connect-rCisServer -Server 'vcsa.domain.org' -User 'administrator@vsphere.local' -Password 'vSphere1!' + + Connect to the CIS service on vCenter vcsa.domain.org with user administrator@vsphere.local + + + + Example 2 + PS C:\> Connect-rCisServer -Server 'vcsa.domain.org' -Credential $cred + + Connect to the CIS service on vCenter vcsa.domain.org with the PSCredential stored in $cred + + + + + + + + Disconnect-rCisServer + Disconnect + rCisServer + + Closes the open connection to the CIS REST API + + + + Closes the open connection to the Cis REST API on the host passed on the Server parameter. + + + + Disconnect-rCisServer + + Server + + The name of the server on which the Cis REST API was opened. + + String + + String + + + None + + + Confirm + + Prompts you for confirmation before running the cmdlet. + + + SwitchParameter + + + False + + + WhatIf + + Shows what would happen if the cmdlet runs. The cmdlet is not run. + + + SwitchParameter + + + False + + + + + + Confirm + + Prompts you for confirmation before running the cmdlet. + + SwitchParameter + + SwitchParameter + + + False + + + Server + + The name of the server on which the Cis REST API was opened. + + String + + String + + + None + + + WhatIf + + Shows what would happen if the cmdlet runs. The cmdlet is not run. + + SwitchParameter + + SwitchParameter + + + False + + + + + + None + + + + + + + + + + System.Object + + + + + + + + + + + + + + Example 1 + PS C:\> Disconnect-rCisServer -Server 'vcsa.domain.org' + + Closes the connection to the server vcsa.domain.org + + + + + + + + Get-rCisTag + Get + rCisTag + + Retrieves Tags from vCenter + + + + Return Tags found on the vCenter. + + + + Get-rCisTag + + Category + + The returned tags are restricted to the category with name passed on this parameter + + PSObject[] + + PSObject[] + + + None + + + Confirm + + Prompts you for confirmation before running the cmdlet. + + + SwitchParameter + + + False + + + Name + + Return the tag(s) with this/these name(s) + + String[] + + String[] + + + None + + + WhatIf + + Shows what would happen if the cmdlet runs. The cmdlet is not run. + + + SwitchParameter + + + False + + + + Get-rCisTag + + Confirm + + Prompts you for confirmation before running the cmdlet. + + + SwitchParameter + + + False + + + Id + + Return the tag with the specific ID + + String[] + + String[] + + + None + + + WhatIf + + Shows what would happen if the cmdlet runs. The cmdlet is not run. + + + SwitchParameter + + + False + + + + + + Category + + The returned tags are restricted to the category with name passed on this parameter + + PSObject[] + + PSObject[] + + + None + + + Confirm + + Prompts you for confirmation before running the cmdlet. + + SwitchParameter + + SwitchParameter + + + False + + + Id + + Return the tag with the specific ID + + String[] + + String[] + + + None + + + Name + + Return the tag(s) with this/these name(s) + + String[] + + String[] + + + None + + + WhatIf + + Shows what would happen if the cmdlet runs. The cmdlet is not run. + + SwitchParameter + + SwitchParameter + + + False + + + + + + System.Management.Automation.PSObject[] + + + + + + + + + + System.Object + + + + + + + + + + + + + + Example 1 + PS C:\> Get-rCisTag -Name MyTag + + Return the tags that are named MyTag + + + + Example 2 + PS C:\> Get-rCisTag -Name MyTag -Category MyCategory + + Return the tags that are named MyTag in the category MyCategory + + + + Example 3 + PS C:\> Get-rCisTag -Id urn:vmomi:InventoryServiceTag:385c90a7-e4ad-49af-a0a5-66fc5fedb254:GLOBAL + + Return the tag with the Id urn:vmomi:InventoryServiceTag:385c90a7-e4ad-49af-a0a5-66fc5fedb254:GLOBAL + + + + Example 4 + PS C:\> Get-rCisTagCategory -Name MyCat | Get-rCisTag + + Return all the Tags in TagCategory MyCat + + + + Example 5 + PS C:\> Get-rCisTag -Name MyTag1,MyTag2 + + Return all the Tags named MyTag1 and MyTag2 + + + + + + + + Get-rCisTagAssignment + Get + rCisTagAssignment + + Return Tag assignments + + + + Return information about all or specific Tag assignments + + + + Get-rCisTagAssignment + + Entity + + Return Tag assignments made to this entity + + PSObject[] + + PSObject[] + + + None + + + Tag + + Return Tag assignments for this Tag + + PSObject[] + + PSObject[] + + + None + + + Category + + Return only Tag assignments for Tags from this specific Category + + PSObject[] + + PSObject[] + + + None + + + Confirm + + Prompts you for confirmation before running the cmdlet. + + + SwitchParameter + + + False + + + WhatIf + + Shows what would happen if the cmdlet runs. The cmdlet is not run. + + + SwitchParameter + + + False + + + + + + Category + + Return only Tag assignments for Tags from this specific Category + + PSObject[] + + PSObject[] + + + None + + + Confirm + + Prompts you for confirmation before running the cmdlet. + + SwitchParameter + + SwitchParameter + + + False + + + Entity + + Return Tag assignments made to this entity + + PSObject[] + + PSObject[] + + + None + + + Tag + + Return Tag assignments for this Tag + + PSObject[] + + PSObject[] + + + None + + + WhatIf + + Shows what would happen if the cmdlet runs. The cmdlet is not run. + + SwitchParameter + + SwitchParameter + + + False + + + + + + System.Management.Automation.PSObject[] + + + + + + + + + + System.Object + + + + + + + + + + + + + + Example 1 + PS C:\> Get-rCisTagAssignment + + Return all Tag assignments + + + + Example 2 + PS C:\> Get-rCisTagAssignment -Entity MyVM + + Return all Tag assignments to entity MyVM + + + + Example 3 + PS C:\> Get-rCisTagAssignment -Entity MyVM -Tag MyTag + + Return the Tag assignment to entity MyVM for a Tag with the name MyTag + + + + Example 4 + PS C:\> Get-rCisTagAssignment -Entity MyVM -Category MyCat + + Return all Tag assignments to entity MyVM with Tags from the Tag Category named MyCat + + + + Example 5 + PS C:\> Get-rCisTagAssignment -Category MyCat + + Return all Tag assignments for all Tags from the Tag Category MyCat + + + + Example 6 + PS C:\> Get-VM MyVM | Get-rCisTagAssignment + + Return all Tag assignments made to entity MyVM + + + + + + + + Get-rCisTagCategory + Get + rCisTagCategory + + Return one or more Tag Categories + + + + Return specific Tag Categories defined on the vCenter. The returned Tag Categories can be filtered by the parameters. + + + + Get-rCisTagCategory + + Confirm + + Prompts you for confirmation before running the cmdlet. + + + SwitchParameter + + + False + + + Id + + The Tag Category Id + + String[] + + String[] + + + None + + + WhatIf + + Shows what would happen if the cmdlet runs. The cmdlet is not run. + + + SwitchParameter + + + False + + + + Get-rCisTagCategory + + Confirm + + Prompts you for confirmation before running the cmdlet. + + + SwitchParameter + + + False + + + Name + + The name of the Tag Category + + String[] + + String[] + + + None + + + WhatIf + + Shows what would happen if the cmdlet runs. The cmdlet is not run. + + + SwitchParameter + + + False + + + + + + Confirm + + Prompts you for confirmation before running the cmdlet. + + SwitchParameter + + SwitchParameter + + + False + + + Id + + The Tag Category Id + + String[] + + String[] + + + None + + + Name + + The name of the Tag Category + + String[] + + String[] + + + None + + + WhatIf + + Shows what would happen if the cmdlet runs. The cmdlet is not run. + + SwitchParameter + + SwitchParameter + + + False + + + + + + None + + + + + + + + + + System.Object + + + + + + + + + + + + + + Example 1 + PS C:\> Get-rCisTagCategory + + Return all Tag Categories + + + + Example 2 + PS C:\> Get-rCisTagCategory -Name Cat1,Cat2 + + Return the Tag Categories named Cat1 and Cat2 + + + + Example 3 + PS C:\> Get-rCisTagCategory -Id urn:vmomi:InventoryServiceCategory:925d8ae1-6b6e-403a-9a12-e78e14b1cdd4:GLOBAL + + Return the Tag Category with Id urn:vmomi:InventoryServiceCategory:925d8ae1-6b6e-403a-9a12-e78e14b1cdd4:GLOBAL + + + + + + + + New-rCisTag + New + rCisTag + + Create a Tag + + + + Create a Tag in one or more Categories, optionally with a Description + + + + New-rCisTag + + Name + + The Name of the new Tag + + String[] + + String[] + + + None + + + Category + + The name of the Category in which to create the Tag + + PSObject + + PSObject + + + None + + + Description + + An optional Description for the Tag + + String + + String + + + None + + + Confirm + + Prompts you for confirmation before running the cmdlet. + + + SwitchParameter + + + False + + + WhatIf + + Shows what would happen if the cmdlet runs. The cmdlet is not run. + + + SwitchParameter + + + False + + + + + + Category + + The name of the Category in which to create the Tag + + PSObject + + PSObject + + + None + + + Confirm + + Prompts you for confirmation before running the cmdlet. + + SwitchParameter + + SwitchParameter + + + False + + + Description + + An optional Description for the Tag + + String + + String + + + None + + + Name + + The Name of the new Tag + + String[] + + String[] + + + None + + + WhatIf + + Shows what would happen if the cmdlet runs. The cmdlet is not run. + + SwitchParameter + + SwitchParameter + + + False + + + + + + System.Management.Automation.PSObject + + + + + + + + + + System.Object + + + + + + + + + + + + + + Example 1 + PS C:\> New-rCisTag -Name MyTag -Category MyCategory + + Creates a Tag named MyTag in the Category MyCategory + + + + Example 2 + PS C:\> New-rCisTag -Name MyTag + + Creates a Tag named MyTag in all Categories + + + + Example 3 + PS C:\> Get-rCisCategory -Name MyCategory | New-rCisTag -Name MyTag -Description 'Text' + + Creates a Tag named MyTag in the Category MyCategory. And add the Description 'Text' to the Tag. + + + + + + + + New-rCisTagAssignment + New + rCisTagAssignment + + Create a new Tag assignment to an Entity + + + + Create a Tag assignment to one more Entities + + + + New-rCisTagAssignment + + Tag + + The name of the Tag to assign to the entity + + String[] + + String[] + + + None + + + Entity + + The name of the Entity or the PowerCLI object for the entity + + PSObject[] + + PSObject[] + + + None + + + Confirm + + Prompts you for confirmation before running the cmdlet. + + + SwitchParameter + + + False + + + WhatIf + + Shows what would happen if the cmdlet runs. The cmdlet is not run. + + + SwitchParameter + + + False + + + + + + Confirm + + Prompts you for confirmation before running the cmdlet. + + SwitchParameter + + SwitchParameter + + + False + + + Entity + + The name of the Entity or the PowerCLI object for the entity + + PSObject[] + + PSObject[] + + + None + + + Tag + + The name of the Tag to assign to the entity + + String[] + + String[] + + + None + + + WhatIf + + Shows what would happen if the cmdlet runs. The cmdlet is not run. + + SwitchParameter + + SwitchParameter + + + False + + + + + + System.Management.Automation.PSObject[] + + + + + + + + + + System.Object + + + + + + + + + + + + + + Example 1 + PS C:\> New-rCisTagAssignment -Tag MyTag -Entity MyVM + + Assign the Tag MyTag to the entity MyVM + + + + Example 2 + PS C:\> Get-VM | New-rCisTagAssignment -Tag MyTag + + Assign the Tag MyTag to all VMs + + + + + + + + New-rCisTagCategory + New + rCisTagCategory + + Create a new Tag Category + + + + Creates a new Tag Category. The user can define the Cardinality of the Tag Catgeory (default Single), add a description to the Tag Category and specify for which entity types the Tag Category can be used. + + + + New-rCisTagCategory + + Name + + The name of the new Tag Category + + String[] + + String[] + + + None + + + Cardinality + + Defines the Cardinality of the Tags in this Tag Category. Possible values are Single (default) and Multiple. + + + Single + Multiple + + String + + String + + + None + + + Description + + A description that is attached to the Tag Category + + String + + String + + + None + + + EntityType + + The type of Entity/Entities to which Tags in this Tag Category can be attached. + + String[] + + String[] + + + None + + + Confirm + + Prompts you for confirmation before running the cmdlet. + + + SwitchParameter + + + False + + + WhatIf + + Shows what would happen if the cmdlet runs. The cmdlet is not run. + + + SwitchParameter + + + False + + + + + + Cardinality + + Defines the Cardinality of the Tags in this Tag Category. Possible values are Single (default) and Multiple. + + String + + String + + + None + + + Confirm + + Prompts you for confirmation before running the cmdlet. + + SwitchParameter + + SwitchParameter + + + False + + + Description + + A description that is attached to the Tag Category + + String + + String + + + None + + + EntityType + + The type of Entity/Entities to which Tags in this Tag Category can be attached. + + String[] + + String[] + + + None + + + Name + + The name of the new Tag Category + + String[] + + String[] + + + None + + + WhatIf + + Shows what would happen if the cmdlet runs. The cmdlet is not run. + + SwitchParameter + + SwitchParameter + + + False + + + + + + None + + + + + + + + + + System.Object + + + + + + + + + + + + + + Example 1 + PS C:\> New-rCisTagCategory -Name MyCat + + Create a new Tag Category named MyCat + + + + Example 2 + PS C:\> New-rCisTagCategory -Name MyCat -Cardinality Multiple -Description 'My Category' + + Create a new Tag Category named MyCat, with a Cardinality of Multiple and a description. + + + + + + + + Remove-rCisTag + Remove + rCisTag + + Remove a Tag + + + + Remove one or more Tags from the environment + + + + Remove-rCisTag + + Tag + + {{Fill Tag Description}} + + PSObject[] + + PSObject[] + + + None + + + Confirm + + Prompts you for confirmation before running the cmdlet. + + + SwitchParameter + + + False + + + WhatIf + + Shows what would happen if the cmdlet runs. The cmdlet is not run. + + + SwitchParameter + + + False + + + + Remove-rCisTag + + Confirm + + Prompts you for confirmation before running the cmdlet. + + + SwitchParameter + + + False + + + WhatIf + + Shows what would happen if the cmdlet runs. The cmdlet is not run. + + + SwitchParameter + + + False + + + Id + + {{Fill Id Description}} + + String[] + + String[] + + + None + + + + + + Confirm + + Prompts you for confirmation before running the cmdlet. + + SwitchParameter + + SwitchParameter + + + False + + + Tag + + {{Fill Tag Description}} + + PSObject[] + + PSObject[] + + + None + + + WhatIf + + Shows what would happen if the cmdlet runs. The cmdlet is not run. + + SwitchParameter + + SwitchParameter + + + False + + + Id + + {{Fill Id Description}} + + String[] + + String[] + + + None + + + + + + System.Management.Automation.PSObject[] + + + + + + + + + + System.Object + + + + + + + + + + + + + + Example 1 + PS C:\> Remove-rCisTag -Name MyTag + + Remove the Tag named MyTag + + + + Example 2 + PS C:\> Remove-rCisTag -Name MyTag + + Remove the Tag named MyTag + + + + + + \ No newline at end of file diff --git a/Modules/rCisTag/rCISTag.psd1 b/Modules/rCisTag/rCISTag.psd1 new file mode 100644 index 0000000000000000000000000000000000000000..a9099d9b4397c79fbc4db9a0aa39ad2317b2deba GIT binary patch literal 5838 zcmcJTT~8ZF6o%&-ssCXmE({g8Aqf$=s1(bD1_@{cg!b0>tE>8}*kGcnf4%Md%<(Y0 z_O4@_Aj|g7&dfRQ`93rM{rkcF?Y8vUc8R-kO?T%~H*yn=`fli2?%wrWTce?75_hZF zfotgb>%xkT=4@@ljrAFdTB@}Z?Qd!IRHKReLr?ssS^20dr1ML||g1&I`7AZRV&GL^t;GN|; zPstFx64&?ozRK`Cb;qK5FRmu(M0^+{*{U5r0|J(3SZ#~!ddUxxN+&gJzUkG1o?w$W0X>_Ew2ihC;R1+?^n_ZXb zWy|H)8lp4pZwlYBxc}*;8fU22MYk{OU|r-iE)RZPYbBm}3Kyc(*Y2Q?3(**89OYsC zNWAdhuH?dl@hI~@_M-Ph_BSkLnlGYb5}(T=*P?JH4oy!Fdnay3FBt$2Av@G(mg;)@ zq+V;$y60ZUseFKFPNa=|l;^ein_rEeO@%oT8lKp3Zo8r~i$D+6ABd;rur;=I(kb}rT zmT7kslV^(R-3?{4-QSYov)3{C)OrT0H2pc4cH(=b6t}OGDU4HlVj;ES1 zw^Z-mZj5#jN39gaVtmA$O1?qk)E)X8x&of)K#nL{?hP|20bhqZud3#NLbw%!Vd=bQf`>JS9ysw%6(Ph}lBX6IVMVv)Y zj=GZR1m|OHF>1+t$UsLz*09qA89SVVn9X+$*;zVXY{wi#8B`ba^I=4~DBX{d_jc@UsWhBll zF}p8YpYM~uN}fHp9!BgrEx}kkSB|lG{qr%BxAE);{TFL<*@|+!%XU2KjjGbSSCf-R^4= zc|K1K>1v`pV4CKH5XPaidina7M|S*#%QO}x_#}Py(C|j|MYTUL~ z%UE8}NtjH7_G|ol~pHl3gF}0?h*d$OHceY3 + + Set-StrictMode -Version 2 + + # You have already run this function + if ([System.Net.ServicePointManager]::CertificatePolicy.ToString() -eq 'IgnoreCerts') { Return } + + $Domain = [AppDomain]::CurrentDomain + $DynAssembly = New-Object System.Reflection.AssemblyName('IgnoreCerts') + $AssemblyBuilder = $Domain.DefineDynamicAssembly($DynAssembly, [System.Reflection.Emit.AssemblyBuilderAccess]::Run) + $ModuleBuilder = $AssemblyBuilder.DefineDynamicModule('IgnoreCerts', $false) + $TypeBuilder = $ModuleBuilder.DefineType('IgnoreCerts', 'AutoLayout, AnsiClass, Class, Public, BeforeFieldInit', [System.Object], [System.Net.ICertificatePolicy]) + $TypeBuilder.DefineDefaultConstructor('PrivateScope, Public, HideBySig, SpecialName, RTSpecialName') | Out-Null + $MethodInfo = [System.Net.ICertificatePolicy].GetMethod('CheckValidationResult') + $MethodBuilder = $TypeBuilder.DefineMethod($MethodInfo.Name, 'PrivateScope, Public, Virtual, HideBySig, VtableLayoutMask', $MethodInfo.CallingConvention, $MethodInfo.ReturnType, ([Type[]] ($MethodInfo.GetParameters() | % {$_.ParameterType}))) + $ILGen = $MethodBuilder.GetILGenerator() + $ILGen.Emit([Reflection.Emit.Opcodes]::Ldc_I4_1) + $ILGen.Emit([Reflection.Emit.Opcodes]::Ret) + $TypeBuilder.CreateType() | Out-Null + + # Disable SSL certificate validation + [System.Net.ServicePointManager]::CertificatePolicy = New-Object IgnoreCerts +} + +function Invoke-vCisRest{ + param ( + [String]$Method, + [String]$Request, + [PSObject]$Body + ) + + Process + { + Write-Verbose -Message "$($MyInvocation.MyCommand.Name)" + Write-Verbose -Message "`t$($PSCmdlet.ParameterSetName)" + Write-Verbose -Message "`tCalled from $($stack = Get-PSCallStack; $stack[1].Command) at $($stack[1].Location)" + + Disable-SSLValidation + + $sRest = @{ + Uri = "https:/",$Script:CisServer.Server,'rest',$Request -join '/' + Method = $Method +# Body = &{if($Body){$Body}} + Body = &{if($Body){$Body | ConvertTo-Json -Depth 32}} + ContentType = 'application/json' + Headers = &{ + if($Script:CisServer.ContainsKey('vmware-api-session-id')){ + @{ + 'vmware-api-session-id' = "$($Script:CisServer.'vmware-api-session-id')" + } + } + else{ + @{ + Authorization = "$($Script:CisServer.AuthHeader)" + } + } + } + } + Try + { +# $result = Invoke-WebRequest @sRest + $result = Invoke-RestMethod @sRest + } + Catch + { + + } + $result + } +} + +function Connect-rCisServer{ + [CmdletBinding(SupportsShouldProcess, ConfirmImpact = 'Low')] + param ( + [Parameter(Mandatory, Position = 1)] + [String]$Server, + [Parameter(Mandatory = $True,ValueFromPipeline = $True, Position = 2, ParameterSetName = 'Credential')] + [System.Management.Automation.PSCredential]$Credential, + [Parameter(Mandatory = $True, Position = 2, ParameterSetName = 'PlainText')] + [String]$User, + [Parameter(Mandatory = $True, Position = 3, ParameterSetName = 'PlainText')] + [String]$Password, + [string]$Proxy, + [Parameter(DontShow)] + [switch]$Fiddler = $false + ) + + Process + { + if ($Proxy) + { + if ($PSDefaultParameterValues.ContainsKey('*:Proxy')) + { + $PSDefaultParameterValues['*:Proxy'] = $Proxy + } + else + { + $PSDefaultParameterValues.Add('*:Proxy', $Proxy) + } + if ($PSDefaultParameterValues.ContainsKey('*:ProxyUseDefaultCredentials')) + { + $PSDefaultParameterValues['*:ProxyUseDefaultCredentials'] = $True + } + else + { + $PSDefaultParameterValues.Add('*:ProxyUseDefaultCredentials', $True) + } + } + if ($PSCmdlet.ParameterSetName -eq 'PlainText') + { + $sPswd = ConvertTo-SecureString -String $Password -AsPlainText -Force + $CisCredential = New-Object System.Management.Automation.PSCredential -ArgumentList ($User, $sPswd) + } + if ($PSCmdlet.ParameterSetName -eq 'Credential') + { + $CisCredential = $Credential + } + if ($Fiddler) + { + if (Get-Process -Name fiddler -ErrorAction SilentlyContinue) + { + if ($PSDefaultParameterValues.ContainsKey('Invoke-RestMethod:Proxy')) + { + $PSDefaultParameterValues['Invoke-RestMethod:Proxy'] = 'http://127.0.0.1:8888' + } + else + { + $PSDefaultParameterValues.Add('Invoke-RestMethod:Proxy', 'http://127.0.0.1:8888') + } + } + } + $Script:CisServer = @{ + Server = $Server + AuthHeader = &{ + $User = $CisCredential.UserName + $Password = $CisCredential.GetNetworkCredential().password + + $Encoded = [System.Text.Encoding]::UTF8.GetBytes(($User, $Password -Join ':')) + $EncodedPassword = [System.Convert]::ToBase64String($Encoded) + "Basic $($EncodedPassword)" + } + } + $sRest = @{ + Method = 'Post' + Request = 'com/vmware/cis/session' + } + If($PSCmdlet.ShouldProcess("CisServer $($Server)")) + { + $result = Invoke-vCisRest @sRest + + $Script:CisServer.Add('vmware-api-session-id',$result.value) + $Script:CisServer.Remove('AuthHeader') + } + } +} + +function Disconnect-rCisServer{ + [CmdletBinding(SupportsShouldProcess = $True, ConfirmImpact = 'High')] + param ( + [Parameter(Mandatory = $True, Position = 1)] + [String]$Server + ) + + Process + { + if($Server -ne $Script:CisServer.Server){ + Write-Warning "You are not connected to server $($Server)" + } + + $sRest = @{ + Method = 'Delete' + Request = 'com/vmware/cis/session' + } + If($PSCmdlet.ShouldProcess("CisServer $($Server)")) + { + $result = Invoke-vCisRest @sRest + $Script:CisServer.Remove('vmware-api-session-id') + } + } +} + +function Get-rCisTag{` + [CmdletBinding(SupportsShouldProcess = $True, ConfirmImpact = 'Low', DefaultParameterSetName='Name')] + param ( + [Parameter(Position = 1, ParameterSetName='Name')] + [String[]]$Name, + [Parameter(Position = 2, ParameterSetName='Name',ValueFromPipeline = $true)] + [PSObject[]]$Category, + [Parameter(Mandatory = $True, Position = 1, ParameterSetName='Id')] + [String[]]$Id + ) + + Process + { + if($PSCmdlet.ParameterSetName -eq 'Name'){ + if($Category){ + $tagIds = $Category | %{ + $categoryIds = &{if($_ -is [string]){ + (Get-rCisTagCategory -Name $_).Id + } + else{ + $_.Id + }} + $categoryIds | %{ + # Get all tags in categories + $sRest = @{ + Method = 'Post' + Request = "com/vmware/cis/tagging/tag/id:$([uri]::EscapeDataString($_))?~action=list-tags-for-category" + } + (Invoke-vCisRest @sRest).value + } + } + } + else{ + $sRest = @{ + Method = 'Get' + Request = 'com/vmware/cis/tagging/tag' + } + $tagIds = (Invoke-vCisRest @sRest).value + } + } + else{ + $tagIds = $Id + } + + # Get category details + $out = @() + $tagIds | where{($PSCmdlet.ParameterSetName -eq 'Id' -and $Id -contains $_) -or $PSCmdlet.ParameterSetName -eq 'Name'} | %{ + $sRest = @{ + Method = 'Get' + Request = "com/vmware/cis/tagging/tag/id:$([uri]::EscapeDataString($_))" + } + $result = Invoke-vCisRest @sRest + + if($PSCmdlet.ParameterSetName -eq 'Id' -or ($PSCmdlet.ParameterSetName -eq 'Name' -and ($Name -eq $null -or $Name -contains $result.value.name))){ + $out += New-Object PSObject -Property @{ + Description = $result.value.description + Id = $result.value.id + Name = $result.value.name + Category = (Get-rCisTagCategory -Id $result.value.category_id).Name + Uid = "$($global:defaultviserver.Id)Tag=$($result.value.id)/" + Client = $global:defaultviserver.Client + } + } + } + $out | Select-Object Category,Description,Id,Name,Uid,Client + } + +} + +function Get-rCisTagCategory{ + [CmdletBinding(SupportsShouldProcess = $True, ConfirmImpact = 'Low', DefaultParameterSetName='Name')] + param ( + [Parameter(Position = 1, ParameterSetName='Name')] + [String[]]$Name, + [Parameter(Mandatory = $True, Position = 1, ParameterSetName='Id')] + [String[]]$Id + ) + + Begin + { + $txtInfo = (Get-Culture).TextInfo + $entityTab = @{ + 'ClusterComputeResource' = 'Cluster' + 'DistributedVirtualSwitch' = 'DistributedSwitch' + 'VmwareDistributedVirtualSwitch' = 'DistributedSwitch' + 'HostSystem' = 'VMHost' + 'DistributedVirtualPortGroup' = 'DistributedPortGroup' + 'VirtualApp' = 'VApp' + 'StoragePod' = 'DatastoreCluster' + 'Network' = 'VirtualPortGroup' + } + } + + Process + { + if($PSCmdlet.ParameterSetName -eq 'Name'){ + # Get all categories + $sRest = @{ + Method = 'Get' + Request = 'com/vmware/cis/tagging/category' + } + $tagCategoryIds = (Invoke-vCisRest @sRest).value + } + else{ + $tagCategoryIds = $Id + } + + # Get category details + $out = @() + $tagCategoryids | where{($PSCmdlet.ParameterSetName -eq 'Id' -and $Id -contains $_) -or $PSCmdlet.ParameterSetName -eq 'Name'} | %{ + $sRest = @{ + Method = 'Get' + Request = "com/vmware/cis/tagging/category/id:$([uri]::EscapeDataString($_))" + } + $result = Invoke-vCisRest @sRest + if($PSCmdlet.ParameterSetName -eq 'Id' -or ($PSCmdlet.ParameterSetName -eq 'Name' -and ($Name -eq $null -or $Name -contains $result.value.name))){ + $out += New-Object PSObject -Property @{ + Description = $result.value.description + Cardinality = $txtInfo.ToTitleCase($result.value.cardinality.ToLower()) + EntityType = @(&{ + if($result.value.associable_types.Count -eq 0){'All'} + else{ + $result.value.associable_types | %{ + if($entityTab.ContainsKey($_)){ + $entityTab.Item($_) + } + else{$_} + } + }} | Sort-Object -Unique) + Id = $result.value.id + Name = $result.value.name + Uid = "$($global:defaultviserver.Id)TagCategory=$($result.value.id)/" + Client = $global:defaultviserver.Client + } + } + } + $out | Select-Object Description,Cardinality,EntityType,Id,Name,Uid,Client + } +} + +function Get-rCisTagAssignment{ + [CmdletBinding(SupportsShouldProcess = $True, ConfirmImpact = 'Low')] + param ( + [parameter(Position = 1, ValueFromPipeline = $true)] + [PSObject[]]$Entity, + [parameter(Position = 2)] + [PSObject[]]$Tag, + [parameter(Position = 3)] + [PSObject[]]$Category + ) + + Begin + { + if($Category.Count -ne 0 -or $Tag.Count -ne 0){ + $tagIds = @((Get-rCisTag -Name $Tag -Category $Category).Id) + } + else{ + $tagIds = @((Get-rCisTag).Id) + } + $out = @() + } + + Process + { + foreach($ent in $Entity){ + if($ent -is [string]){ + $ent = Get-Inventory -Name $ent -ErrorAction SilentlyContinue + } + + $entMoRef = New-Object PSObject -Property @{ + type = $ent.ExtensionData.MoRef.Type + id = $ent.ExtensionData.MoRef.Value + } + $sRest = @{ + Method = 'Post' + Request = 'com/vmware/cis/tagging/tag-association?~action=list-attached-tags-on-objects' + Body = @{ + object_ids = @($entMoRef) + } + } + $tagObj = (Invoke-vCisRest @sRest).value + foreach($obj in @($tagObj)){ + foreach($tag in ($obj.tag_ids | where{$tagIds -contains $_})){ + $sMoRef = "$($obj.object_id.type)-$($obj.object_id.id)" + $out += New-Object PSObject -Property @{ + Entity = (Get-View -id $sMoRef -Property Name).Name + Tag = (Get-rCisTag -Id $tag).Name + Id = 'com.vmware.cis.tagging.TagAssociationModel' + Name = 'com.vmware.cis.tagging.TagAssociationModel' + Uid = "$($global:defaultviserver.Id)VirtualMachine=$($sMoRef)/TagAssignment=/Tag=$($tag.tag_id)/" + Client = $global:defaultviserver.Client + } + } + } + } + } + + End + { + if($out.Count -eq 0) + { + $sRest = @{ + Method = 'Post' + Request = 'com/vmware/cis/tagging/tag-association?~action=list-attached-objects-on-tags' + Body = @{ + tag_ids = $tagIds + } + } + $tagObj = (Invoke-vCisRest @sRest).value + $out = foreach($tag in @(($tagObj | where{$tagIds -contains $_.tag_id}))){ + foreach($obj in $tag.object_ids){ + $sMoRef = "$($obj.type)-$($obj.id)" + New-Object PSObject -Property @{ + Entity = (Get-View -id $sMoRef -Property Name).Name + Tag = (Get-rCisTag -Id $tag.tag_id).Name + Id = 'com.vmware.cis.tagging.TagAssociationModel' + Name = 'com.vmware.cis.tagging.TagAssociationModel' + Uid = "$($global:defaultviserver.Id)VirtualMachine=$($sMoRef)/TagAssignment=/Tag=$($tag.tag_id)/" + Client = $global:defaultviserver.Client + } + } + } + } + + $out | Select-Object Uid,Tag,Entity,Id,Name,Client + } +} + +function New-rCisTag{ + [CmdletBinding(SupportsShouldProcess = $True, ConfirmImpact = 'High')] + param ( + [Parameter(Mandatory=$true, Position = 1)] + [String[]]$Name, + [Parameter(Mandatory=$true, Position = 2,ValueFromPipeline = $true)] + [PSObject]$Category, + [Parameter(Position = 3)] + [string]$Description + ) + + Process + { + $out = @() + if($Category -is [String]){ + $Category = Get-rCisTagCategory -Name $Category + } + $Name | %{ + $sRest = @{ + Method = 'Post' + Request = 'com/vmware/cis/tagging/tag' + Body = @{ + create_spec = @{ + category_id = $Category.Id + name = $_ + description = $Description + } + } + } + $tagId = (Invoke-vCisRest @sRest).value + $out += New-Object PSObject -Property @{ + Category = $Category.Name + Description = $Description + Id = $tagId + Name = $_ + Uid = "$($global:defaultviserver.Id)Tag=$($tagId)/" + Client = $global:defaultviserver.Client + } + } + $out | Select-Object Category,Description,Id,Name,Uid,Client + } +} + +function New-rCisTagCategory{ + [CmdletBinding(SupportsShouldProcess = $True, ConfirmImpact = 'High')] + param ( + [Parameter(Mandatory=$true, Position = 1)] + [String[]]$Name, + [Parameter(Position = 2)] + [ValidateSet('Single','Multiple')] + [string]$Cardinality = 'Single', + [Parameter(Position = 3)] + [string]$Description, + [Parameter(Position = 4)] + [string[]]$EntityType + ) + + Process + { + $out = @() + $Name | %{ + $sRest = @{ + Method = 'Post' + Request = 'com/vmware/cis/tagging/category' + Body = @{ + create_spec = @{ + cardinality = $Cardinality.ToUpper() + associable_types = @($EntityType) + name = $_ + description = $Description + } + } + } + $categoryId = (Invoke-vCisRest @sRest).value + $out += New-Object PSObject -Property @{ + Description = $Description + Cardinality = $Cardinality + EntityType = @($EntityType) + Id = $categoryId + Name = $_ + Uid = "$($global:defaultviserver.Id)TagCategory=$($categoryId)/" + Client = $global:defaultviserver.Client + } + } + $out | Select-Object Description,Cardinality,EntityType,Id,Name,Uid,Client + } +} + +function New-rCisTagAssignment{ + [CmdletBinding(SupportsShouldProcess = $True, ConfirmImpact = 'High')] + param ( + [Parameter(Mandatory=$true, Position = 1)] + [String[]]$Tag, + [Parameter(Mandatory=$true,ValueFromPipeline = $true, Position = 2)] + [PSObject[]]$Entity + ) + + Process + { + $tagIds = @((Get-rCisTag -Name $Tag).Id) + $Entity = foreach($ent in $Entity){ + if($ent -is [string]){ + $ent = Get-Inventory -Name $ent -ErrorAction SilentlyContinue + } + $entMoRef = New-Object PSObject -Property @{ + type = $ent.ExtensionData.MoRef.Type + id = $ent.ExtensionData.MoRef.Value + } + foreach($tagId in $tagIds){ + $sRest = @{ + Method = 'Post' + Request = "com/vmware/cis/tagging/tag-association/id:$($tagId)?~action=attach" + Body = @{ + object_id = $entMoRef + } + } + Invoke-vCisRest @sRest + } + } + } + +# foreach($ent in +# if($Tag.Count -eq 1) +# { +# $tagId = (Get-rCisTag -Name $Tag).Id +# } +# elseif($Tag.Count -gt 1) +# { +# $tagIds = (Get-rCisTag -Name $Tag).Id +# } +# $Entity = foreach($ent in $Entity){ +# if($ent -is [string]){ +# Get-Inventory -Name $ent -ErrorAction SilentlyContinue +# } +# else{$ent} +# } +# +# if($Entity.Count -eq 1) +# { +# $entMoRef = New-Object PSObject -Property @{ +# type = $Entity[0].ExtensionData.MoRef.Type +# id = $Entity[0].ExtensionData.MoRef.Value +# } +# if($tag.Count -eq 1){ +# $sRest = @{ +# Method = 'Post' +# Request = "com/vmware/cis/tagging/tag-association/id:$($tagId)?~action=attach" +# Body = @{ +# object_id = $entMoRef +# } +# } +# Invoke-vCisRest @sRest +# } +# elseif($Tag.Count -gt 1){ +# $sRest = @{ +# Method = 'Post' +# Request = 'com/vmware/cis/tagging/tagassociation?~action=attach-multiple-tags-to-object' +# Body = @{ +# object_id = $entMoRef +# tag_ids = @($tagIds) +# } +# } +# Invoke-vCisRest @sRest +# } +# } +# elseif($Entity.Count -gt 1) +# { +# $entMorefs = $Entity | %{ +# New-Object PSObject -Property @{ +# type = $_.ExtensionData.MoRef.Type +# id = $_.ExtensionData.MoRef.Value +# } +# } +# if($tag.Count -eq 1){ +# $sRest = @{ +# Method = 'Post' +# Request = 'com/vmware/cis/tagging/tagassociation/id:$($tagId)?~action=attach-tag-to-multiple-objects' +# Body = @{ +# objects_ids = @($entMoRefs) +# tag_id = $tagId +# } +# } +# Invoke-vCisRest @sRest +# } +# elseif($Tag.Count -gt 1){ +# $tagIds | %{ +# $sRest = @{ +# Method = 'Post' +# Request = 'com/vmware/cis/tagging/tagassociation/id:$($tagId)?~action=attach-tag-to-multiple-objects' +# Body = @{ +# objects_ids = @($entMoRefs) +# tag_id = $_ +# } +# } +# Invoke-vCisRest @sRest +# } +# } +# } +# } +} + +function Remove-rCisTag{ + [CmdletBinding(SupportsShouldProcess = $True, ConfirmImpact = 'High', DefaultParameterSetName='Name')] + param ( + [Parameter(Mandatory=$true, Position = 1, ValueFromPipeline = $true,ParameterSetName='Name')] + [PSObject[]]$Tag, + [Parameter(Mandatory=$true, Position = 1, ValueFromPipelineByPropertyName = $true,ParameterSetName='Id')] + [String[]]$Id + ) + + Process + { + if($PSCmdlet.ParameterSetName -eq 'Name'){ + foreach($tagObj in $Tag){ + if($tagObj -is [string]){ + $tagObj = Get-rCisTag -Name $tagObj + } + $sRest = @{ + Method = 'Delete' + Request = "com/vmware/cis/tagging/tag/id:$($tagObj.Id)" + } + Invoke-vCisRest @sRest + } + } + else{ + foreach($tagId in $Id){ + $sRest = @{ + Method = 'Delete' + Request = "com/vmware/cis/tagging/tag/id:$($tagId)" + } + Invoke-vCisRest @sRest + } + } + } +} + +function Remove-rCisTagCategory{ + [CmdletBinding(SupportsShouldProcess = $True, ConfirmImpact = 'High', DefaultParameterSetName='Name')] + param ( + [Parameter(Mandatory=$true,Position = 1, ValueFromPipeline = $true,ParameterSetName='Name')] + [PSObject[]]$Category, + [Parameter(Mandatory=$true,Position = 1, ValueFromPipelineByPropertyName = $true,ParameterSetName='Id')] + [String[]]$Id + ) + + Process + { + if($PSCmdlet.ParameterSetName -eq 'Name'){ + foreach($catObj in $Category){ + if($catObj -is [string]){ + $catObj = Get-rCisTagCategory -Name $catObj + } + $sRest = @{ + Method = 'Delete' + Request = "com/vmware/cis/tagging/category/id:$($catObj.Id)" + } + Invoke-vCisRest @sRest + } + } + else{ + foreach($catId in $Id){ + $sRest = @{ + Method = 'Delete' + Request = "com/vmware/cis/tagging/category/id:$($catId)" + } + Invoke-vCisRest @sRest + } + } + } +} + +function Remove-rCisTagAssignment{ + [CmdletBinding(SupportsShouldProcess = $True, ConfirmImpact = 'High',DefaultParameterSetName='Assignment')] + param ( + [Parameter(Mandatory=$true, Position = 1, ValueFromPipeline = $true,ParameterSetName='Assignment')] + [PSObject[]]$TagAssignment, + [Parameter(Mandatory=$true,Position = 1, ValueFromPipeline = $true,ParameterSetName='Name')] + [string[]]$Tag, + [Parameter(Position = 2, ParameterSetName='Name')] + [string[]]$Category, + [Parameter(Mandatory=$true, ValueFromPipelineByPropertyName = $true,ParameterSetName='Id')] + [string[]]$TagId, + [Parameter(ParameterSetName='Name')] + [Parameter(ParameterSetName='Id')] + [PSObject[]]$Entity + ) + + Process + { + + switch ($PSCmdlet.ParameterSetName){ + 'Name' { + $TagAssignment = Get-rCisTagAssignment -Entity $Entity -Tag $Tag -Category $Category + } + 'Id' { + $tags = Get-rCisTag -Id $TagId + $TagAssignment = Get-rCisTagAssignment -Tag $tags.Name -Entity $Entity + } + } + if($TagAssignment){ + $entMoRefs = @(Get-Inventory -Name $TagAssignment.Entity -ErrorAction SilentlyContinue | %{ + New-Object PSObject -Property @{ + type = $_.ExtensionData.MoRef.Type + id = $_.ExtensionData.MoRef.Value + } + }) + $tagIds = @((Get-rCisTag -Name $TagAssignment.Tag).Id) + } + + foreach($entMoRef in $entMoRefs){ + foreach($tId in $tagIds){ + $sRest = @{ + Method = 'Post' + Request = "com/vmware/cis/tagging/tag-association/id:$($tId)?~action=detach" + Body = @{ + object_id = $entMoRef + } + } + Invoke-vCisRest @sRest + } + } + } +} + +function Set-rCisTag{ + [CmdletBinding(SupportsShouldProcess = $True, ConfirmImpact = 'High')] + param ( + [Parameter(Mandatory=$true, Position = 1, ValueFromPipeline = $true)] + [PSObject[]]$Tag, + [Parameter(Position = 2)] + [string]$Name, + [Parameter(Position = 3)] + [string]$Description + ) + + Process + { + foreach($tagObj in $Tag){ + if($tagObj -is [string]){ + $tagObj = Get-rCisTag -Name $tagObj + } + $sRest = @{ + Method = 'Patch' + Request = "com/vmware/cis/tagging/tag/id:$($tagObj.Id)" + Body = @{ + update_spec = @{ + name = $Name + description = $Description + } + } + } + Invoke-vCisRest @sRest + } + } +} + +function Set-rCisTagCategory{ + [CmdletBinding(SupportsShouldProcess = $True, ConfirmImpact = 'High')] + param ( + [Parameter(Mandatory=$true, Position = 1, ValueFromPipeline = $true)] + [PSObject[]]$Category, + [Parameter(Position = 2)] + [string]$Name, + [Parameter(Position = 3)] + [ValidateSet('Single','Multiple')] + [string]$Cardinality, # Only SINGLE to MULTIPLE +# [string[]]$AddEntityType, # Does not work + [string]$Description + ) + + Process + { + foreach($catObj in $Category){ + if($catObj -is [string]){ + $catObj = Get-rCisTagCategory -Name $catObj + } + $sRest = @{ + Method = 'Patch' + Request = "com/vmware/cis/tagging/category/id:$($catObj.Id)" + Body = @{ + update_spec = @{ + } + } + } + if($Name){ + $sRest.Body.update_spec.Add('name',$Name) + } + if($Description){ + $sRest.Body.update_spec.Add('description',$Description) + } + if($Cardinality -and $catObj.Cardinality -eq 'SINGLE'){ + $sRest.Body.update_spec.Add('cardinality',$Cardinality.ToUpper()) + } + if($Name -or $Description -or $Cardinality){ + Invoke-vCisRest @sRest + } + } + } +} From 6c50bef798a2e3a23c6f3af75ddd1e637f19db7d Mon Sep 17 00:00:00 2001 From: LucD Date: Sat, 2 Dec 2017 23:25:35 +0100 Subject: [PATCH 20/29] rCisTag-Examples Add examples to rCisTag module --- Modules/rCisTag/Examples/01-Get.ps1 | 17 ++++++++++++++++ Modules/rCisTag/Examples/02-New.ps1 | 14 +++++++++++++ Modules/rCisTag/Examples/03-Set.ps1 | 11 ++++++++++ Modules/rCisTag/Examples/04-Remove.ps1 | 13 ++++++++++++ Modules/rCisTag/Examples/05-Tag-Datastore.ps1 | 20 +++++++++++++++++++ Modules/rCisTag/Examples/CisConfig.ps1 | 3 +++ 6 files changed, 78 insertions(+) create mode 100644 Modules/rCisTag/Examples/01-Get.ps1 create mode 100644 Modules/rCisTag/Examples/02-New.ps1 create mode 100644 Modules/rCisTag/Examples/03-Set.ps1 create mode 100644 Modules/rCisTag/Examples/04-Remove.ps1 create mode 100644 Modules/rCisTag/Examples/05-Tag-Datastore.ps1 create mode 100644 Modules/rCisTag/Examples/CisConfig.ps1 diff --git a/Modules/rCisTag/Examples/01-Get.ps1 b/Modules/rCisTag/Examples/01-Get.ps1 new file mode 100644 index 0000000..52cf4de --- /dev/null +++ b/Modules/rCisTag/Examples/01-Get.ps1 @@ -0,0 +1,17 @@ +# Fetch Cis Server hostname and credentials +.\CisConfig.ps1 + + +Connect-rCisServer -Server $cisServer -User $cisUser -Password $cisPswd + +# Get Tag information +Get-rCisTag + +# Get Tag Category information +Get-rCisTagCategory + +# Get Tag Assignment information +Get-rCisTagAssignment + +Disconnect-rCisServer -Server $cisServer -Confirm:$false + \ No newline at end of file diff --git a/Modules/rCisTag/Examples/02-New.ps1 b/Modules/rCisTag/Examples/02-New.ps1 new file mode 100644 index 0000000..7fe9af2 --- /dev/null +++ b/Modules/rCisTag/Examples/02-New.ps1 @@ -0,0 +1,14 @@ +# Fetch Cis Server hostname and credentials +.\CisConfig.ps1 + +Connect-rCisServer -Server $cisServer -User $cisUser -Password $cisPswd + +New-rCisTagCategory -Name MyCat1 -Cardinality Single -Description 'Test Tag Category' -EntityType 'VirtualMachine' +New-rCisTag -Name MyTag1 -Category MyCat1 -Description 'Test Tag' +$vm = Get-VM | Get-Random +New-rCisTagAssignment -Entity $vm -Tag MyTag1 + +Get-rCisTagAssignment -Tag MyTag1 + +Disconnect-rCisServer -Server $cisServer -Confirm:$false + \ No newline at end of file diff --git a/Modules/rCisTag/Examples/03-Set.ps1 b/Modules/rCisTag/Examples/03-Set.ps1 new file mode 100644 index 0000000..35d26b0 --- /dev/null +++ b/Modules/rCisTag/Examples/03-Set.ps1 @@ -0,0 +1,11 @@ +# Fetch Cis Server hostname and credentials +.\CisConfig.ps1 + +Connect-rCisServer -Server $cisServer -User $cisUser -Password $cisPswd + +Get-rCisTag -Name MyTag1 | Set-rCisTag -Name MyNewTag1 -Description 'Name changed' + +Get-rCisTagCategory -Name MyCat1 | Set-rCisTagCategory -Cardinality Multiple -Name MyNewCat1 -Description 'Name changed' + +Disconnect-rCisServer -Server $cisServer -Confirm:$false + \ No newline at end of file diff --git a/Modules/rCisTag/Examples/04-Remove.ps1 b/Modules/rCisTag/Examples/04-Remove.ps1 new file mode 100644 index 0000000..2f684f9 --- /dev/null +++ b/Modules/rCisTag/Examples/04-Remove.ps1 @@ -0,0 +1,13 @@ +# Fetch Cis Server hostname and credentials +.\CisConfig.ps1 + +Connect-rCisServer -Server $cisServer -User $cisUser -Password $cisPswd + +Get-rCisTagAssignment -Tag MyNewTag1 | Remove-rCisTagAssignment -Confirm:$false + +Get-rCisTag -Name MyNewTag1 | Remove-rCisTag -Confirm:$false + +Get-rCisTagCategory -Name MyNewCat1 | Remove-rCisTagCategory -Confirm:$false + +Disconnect-rCisServer -Server $cisServer -Confirm:$false + \ No newline at end of file diff --git a/Modules/rCisTag/Examples/05-Tag-Datastore.ps1 b/Modules/rCisTag/Examples/05-Tag-Datastore.ps1 new file mode 100644 index 0000000..f0ad343 --- /dev/null +++ b/Modules/rCisTag/Examples/05-Tag-Datastore.ps1 @@ -0,0 +1,20 @@ +# Fetch Cis Server hostname and credentials +.\CisConfig.ps1 + +Connect-rCisServer -Server $cisServer -User $cisUser -Password $cisPswd + +$catName = 'Homelab' + +# Clean up +Get-rCisTagCategory -Name $catName | Remove-rCisTagCategory -Confirm:$false + +# Tag all datastores with their type +New-rCisTagCategory -Name HomeLab -Description 'Homelab datastores' -Cardinality Single -EntityType 'Datastore' | +New-rCisTag -Name 'VMFS','NFS' -Description 'Datastore type' + +Get-Cluster -Name Cluster1 | Get-Datastore | %{ + New-rCisTagAssignment -Entity $_ -Tag "$($_.Type)" +} + +Disconnect-rCisServer -Server $cisServer -Confirm:$false + \ No newline at end of file diff --git a/Modules/rCisTag/Examples/CisConfig.ps1 b/Modules/rCisTag/Examples/CisConfig.ps1 new file mode 100644 index 0000000..de72021 --- /dev/null +++ b/Modules/rCisTag/Examples/CisConfig.ps1 @@ -0,0 +1,3 @@ +$cisServer = 'vcsa.my.domain' +$cisUser = 'administrator@vsphere.local' +$cisPswd = 'VMware1!' From b5800f0eff9eb4e16a1fe93b8ea1827d709f072f Mon Sep 17 00:00:00 2001 From: William Lam Date: Wed, 20 Dec 2017 08:37:38 -0800 Subject: [PATCH 21/29] PowerCLI Module using Cross vCenter Migration Utility Fling API --- Modules/CrossvCentervmotion/XVM.psm1 | 290 +++++++++++++++++++++++++++ 1 file changed, 290 insertions(+) create mode 100644 Modules/CrossvCentervmotion/XVM.psm1 diff --git a/Modules/CrossvCentervmotion/XVM.psm1 b/Modules/CrossvCentervmotion/XVM.psm1 new file mode 100644 index 0000000..aef65c8 --- /dev/null +++ b/Modules/CrossvCentervmotion/XVM.psm1 @@ -0,0 +1,290 @@ +Function Get-XVCMStatus { +<# + .NOTES + =========================================================================== + Created by: William Lam + Organization: VMware + Blog: www.virtuallyghetto.com + Twitter: @lamw + =========================================================================== + .DESCRIPTION + This function returns whether Cross vCenter Workload Migration Utility is running or not + .EXAMPLE + Get-XVCMStatus +#> + $Uri = "http://localhost:8080/api/ping" + + $results = Invoke-WebRequest -Uri $Uri -Method GET -TimeoutSec 5 + + if($results.StatusCode -eq 200) { + Write-Host -ForegroundColor Green $results.Content + } else { Write-Host -ForegroundColor Red "Cross vCenter Workload Migration Utility is probably not running" } +} + +Function Get-XVCMSite { +<# + .NOTES + =========================================================================== + Created by: William Lam + Organization: VMware + Blog: www.virtuallyghetto.com + Twitter: @lamw + =========================================================================== + .DESCRIPTION + This function returns all registered vCenter Servers + .EXAMPLE + Get-XVCMSite +#> + $Uri = "http://localhost:8080/api/sites" + + $results = Invoke-WebRequest -Uri $Uri -Method GET + + if($results.StatusCode -eq 200) { + ($results.Content | ConvertFrom-Json)|select sitename,hostname,username + } else { Write-Host -ForegroundColor Red "Failed to retrieve VC Site Registration details" } +} + +Function New-XVCMSite { +<# + .NOTES + =========================================================================== + Created by: William Lam + Organization: VMware + Blog: www.virtuallyghetto.com + Twitter: @lamw + =========================================================================== + .DESCRIPTION + This function registers a new vCenter Server endpoint + .PARAMETER SiteName + The display name for the particular vCenter Server to be registered + .PARAMETER VCHostname + The Hostname/IP Address of vCenter Server + .PARAMETER VCUsername + The VC Username of vCenter Server + .PARAMETER VCPassword + The VC Password of vCenter Server + .PARAMETER Insecure + Flag to disable SSL Verification checking, useful for lab environments + .EXAMPLE + New-XVCMSite -SiteName "SiteA" -VCHostname "vcenter65-1.primp-industries.com" -VCUsername "administrator@vsphere.local" -VCPassword "VMware1!" -Insecure +#> + param( + [Parameter(Mandatory=$true)][String]$SiteName, + [Parameter(Mandatory=$true)][String]$VCHostname, + [Parameter(Mandatory=$true)][String]$VCUsername, + [Parameter(Mandatory=$true)][String]$VCPassword, + [Parameter(Mandatory=$false)][Switch]$Insecure + ) + + $Uri = "http://localhost:8080/api/sites" + + $insecureFlag = $false + if($Insecure) { + $insecureFlag = $true + } + + $body = @{ + "sitename"=$SiteName; + "hostname"=$VCHostname; + "username"=$VCUsername; + "password"=$VCPassword; + "insecure"=$insecureFlag; + } + + $body = $body | ConvertTo-Json + + Write-Host -ForegroundColor Cyan "Registering vCenter Server $VCHostname as $SiteName ..." + $results = Invoke-WebRequest -Uri $Uri -Method POST -Body $body -ContentType "application/json" + + if($results.StatusCode -eq 200) { + Write-Host -ForegroundColor Green "Successfully registered $SiteName" + } else { Write-Host -ForegroundColor Red "Failed to register $SiteName" } +} + +Function Remove-XVCMSite { +<# + .NOTES + =========================================================================== + Created by: William Lam + Organization: VMware + Blog: www.virtuallyghetto.com + Twitter: @lamw + =========================================================================== + .DESCRIPTION + This function removes vCenter Server endpoint + .PARAMETER SiteName + The name of the registered vCenter Server to remove + .EXAMPLE + Remove-XVCMSite -SiteName "SiteA" +#> + param( + [Parameter(Mandatory=$true)][String]$SiteName + ) + + $Uri = "http://localhost:8080/api/sites/$SiteName" + + Write-Host -ForegroundColor Cyan "Deleting vCenter Server Site Registerion $SiteName ..." + $results = Invoke-WebRequest -Uri $Uri -Method DELETE + + if($results.StatusCode -eq 200) { + Write-Host -ForegroundColor Green "Successfully deleted $SiteName" + } else { Write-Host -ForegroundColor Red "Failed to deleted $SiteName" } +} + +Function New-XVCMRequest { +<# + .NOTES + =========================================================================== + Created by: William Lam + Organization: VMware + Blog: www.virtuallyghetto.com + Twitter: @lamw + =========================================================================== + .DESCRIPTION + This function initiates a migration request + .PARAMETER SrcSite + The name of the source vCenter Server + .PARAMETER DstSite + The name of the destination vCenter Server + .PARAMETER SrcDatacenter + The name of the source vSphere Datacenter + .PARAMETER DstDatacenter + The name of the destination vSphere Datacenter + .PARAMETER SrcCluster + The name of the source vSphere Cluster + .PARAMETER DstCluster + The name of the destination vSphere Cluster + .PARAMETER DstDatastore + The name of the destination Datastore + .PARAMETER srcVMs + List of VMs to migrate + .PARAMETER NetworkMapping + Hash table of the VM network mappings between your source and destination vCenter Server + .EXAMPLE + New-XVCMRequest -SrcSite SiteA -DstSite SiteB ` + -SrcDatacenter Datacenter-SiteA -DstDatacenter Datacenter-SiteB ` + -SrcCluster Palo-Alto -DstCluster Santa-Barbara ` + -DstDatastore vsanDatastore ` + -srcVMs @("PhotonOS-01","PhotonOS-02","PhotonOS-03","PhotonOS-04") ` + -NetworkMapping @{"DVPG-VM Network 1"="DVPG-Internal Network";"DVPG-VM Network 2"="DVPG-External Network"} +#> + param( + [Parameter(Mandatory=$true)][String]$SrcSite, + [Parameter(Mandatory=$true)][String]$DstSite, + [Parameter(Mandatory=$true)][String]$SrcDatacenter, + [Parameter(Mandatory=$true)][String]$DstDatacenter, + [Parameter(Mandatory=$true)][String]$SrcCluster, + [Parameter(Mandatory=$true)][String]$DstCluster, + [Parameter(Mandatory=$true)][String]$DstDatastore, + [Parameter(Mandatory=$true)][String[]]$srcVMs, + [Parameter(Mandatory=$true)][Hashtable]$NetworkMapping + ) + + $Uri = "http://localhost:8080/api/tasks" + + $body = @{ + "sourceSite"=$SrcSite; + "targetSite"=$DstSite; + "sourceDatacenter"=$SrcDatacenter; + "targetDatacenter"=$dstDatacenter; + "sourceCluster"=$SrcCluster; + "targetCluster"=$DstCluster; + "targetDatastore"=$DstDatastore; + "networkMap"=$NetworkMapping; + "vmList"=$srcVMs; + } + + $body = $body | ConvertTo-Json + + Write-Host -ForegroundColor Cyan "Initiating migration request ..." + $results = Invoke-WebRequest -Uri $Uri -Method POST -Body $body -ContentType "application/json" + + if($results.StatusCode -eq 200) { + $taskId = ($results.Content | ConvertFrom-Json).requestId + Write-Host -ForegroundColor Green "Successfully issued migration with TaskID: $taskId" + } else { Write-Host -ForegroundColor Red "Failed to initiate migration request" } +} + +Function Get-XVCMTask { +<# + .NOTES + =========================================================================== + Created by: William Lam + Organization: VMware + Blog: www.virtuallyghetto.com + Twitter: @lamw + =========================================================================== + .DESCRIPTION + This function retrieves either all migration tasks and/or a specific migration task + .PARAMETER Id + The task ID returned from initiating a migration + .EXAMPLE + Get-XVCMTask -Id +#> + param( + [Parameter(Mandatory=$false)][String]$Id + ) + + $Uri = "http://localhost:8080/api/tasks" + + if($Id) { + $body = @{"requestId"=$Id} + + $results = Invoke-WebRequest -Uri $Uri -Method GET -Body $body -ContentType "application/json" + } else { + $results = Invoke-WebRequest -Uri $Uri -Method GET + } + + if($results.StatusCode -eq 200) { + $results.Content | ConvertFrom-Json + } else { Write-Host -ForegroundColor Red "Failed to retrieve tasks" } +} + +Function Get-VMNetwork { +<# + .NOTES + =========================================================================== + Created by: William Lam + Organization: VMware + Blog: www.virtuallyghetto.com + Twitter: @lamw + =========================================================================== + .DESCRIPTION + This function returns the list of all VM Networks attached to + given VMs to help with initiating migration + .PARAMETER srcVMs + List of VMs to query their current VM Networks + .EXAMPLE + Get-VMNetwork -srcVMs @("PhotonOS-01","PhotonOS-02","PhotonOS-03","PhotonOS-04") +#> + param( + [Parameter(Mandatory=$false)][String[]]$srcVMs + ) + + if (-not $global:DefaultVIServers) { Write-Host -ForegroundColor red "No vCenter Server Connection found, please connect to your source vCenter Server using Connect-VIServer"; break } + + $results = @() + if($srcVMs) { + foreach ($srcVM in $srcVMs) { + $vm = Get-VM -Name $srcVM + $networkDetails = $vm | Get-NetworkAdapter + $tmp = [pscustomobject] @{ + Name = $srcVM; + Adapter = $networkDetails.name; + Network = $networkDetails.NetworkName; + } + $results+=$tmp + } + } else { + foreach ($vm in Get-VM) { + $networkDetails = $vm | Get-NetworkAdapter + $tmp = [pscustomobject] @{ + Name = $vm.Name; + Adapter = $networkDetails.name; + Network = $networkDetails.NetworkName; + } + $results+=$tmp + } + } + $results +} \ No newline at end of file From 23f215be3596fbc3b89e25a963ddef69cbd0a7d7 Mon Sep 17 00:00:00 2001 From: Kyle Ruddy Date: Fri, 5 Jan 2018 16:13:39 -0500 Subject: [PATCH 22/29] Update VMToolsManagement.psm1 Added advanced function: Get-VMToolsUpgradePolicy Updated the following advanced functions to add functionatlity: - Set-VMToolsUpgradePolicy - Supports UpgradeAtPowerCycle and Manual - Update-VMToolsConfInVM - Supports all log levels now Misc other minor updates: - cmdlets changed to 'advanced function' - 'vcetner' changed to 'vcenter' --- .../VMToolsManagement/VMToolsManagement.psm1 | 257 ++++++++++++------ 1 file changed, 173 insertions(+), 84 deletions(-) diff --git a/Modules/VMToolsManagement/VMToolsManagement.psm1 b/Modules/VMToolsManagement/VMToolsManagement.psm1 index bbfdf5e..335476d 100644 --- a/Modules/VMToolsManagement/VMToolsManagement.psm1 +++ b/Modules/VMToolsManagement/VMToolsManagement.psm1 @@ -1,4 +1,4 @@ -# Script Module : VMToolsManagement +# Script Module : VMToolsManagement # Version : 1.0 # Copyright © 2017 VMware, Inc. All Rights Reserved. @@ -37,10 +37,10 @@ New-VIProperty -Name ToolsBuildNumber -Object VirtualMachine -Value { Function Get-VMToolsInfo { <# .SYNOPSIS - This cmdlet retrieves the VMTools info of specified virtual machines. + This advanced function retrieves the VMTools info of specified virtual machines. .DESCRIPTION - This cmdlet retrieves the VMTools version and build number info of specified virtual machines. + This advanced function retrieves the VMTools version and build number info of specified virtual machines. .PARAMETER VM Specifies the virtual machines which you want to get the VMTools info of. @@ -50,7 +50,7 @@ Function Get-VMToolsInfo { C:\PS> $VCServer = Connect-VIServer -Server -User -Password C:\PS> Get-VM -Server $VCServer | Get-VMToolsInfo - Retrieves VMTools info of all virtual machines which run in the $VCServer vCetner Server. + Retrieves VMTools info of all virtual machines which run in the $VCServer vCenter Server. .EXAMPLE C:\PS> Get-VM "*rhel*" | Get-VMToolsInfo @@ -74,7 +74,7 @@ Function Get-VMToolsInfo { Retrieves VMTools info of virtual machines which run on the "MyESXiHostName" ESXi host. .NOTES - This cmdlet assumes that you are connected to at least one vCenter Server system. + This advanced function assumes that you are connected to at least one vCenter Server system. The tools build number is not supported in VMTools before 10.2.0 .NOTES @@ -100,17 +100,17 @@ Function Get-VMToolsInfo { ) Process { - Get-VM $VM | Select Name, @{Name="ToolsVersion"; Expression={$_.Guest.ToolsVersion}}, ToolsBuildNumber + Get-VM $VM | Select-Object Name, @{Name="ToolsVersion"; Expression={$_.Guest.ToolsVersion}}, ToolsBuildNumber } } Function Get-VMToolsInstallLastError { <# .SYNOPSIS - This cmdlet retrieves the error code of last VMTools installation. + This advanced function retrieves the error code of last VMTools installation. .DESCRIPTION - This cmdlet retrieves the error code of last VMTools installation on specified virtual machines. + This advanced function retrieves the error code of last VMTools installation on specified virtual machines. .PARAMETER VM Specifies the virtual machines which you want to get the error code of. @@ -120,7 +120,7 @@ Function Get-VMToolsInstallLastError { C:\PS> $VCServer = Connect-VIServer -Server -User -Password C:\PS> Get-VM -Server $VCServer | Get-VMToolsInstallLastError - Retrieves the last VMTools installation error code of all virtual machines which run in the $VCServer vCetner Server. + Retrieves the last VMTools installation error code of all virtual machines which run in the $VCServer vCenter Server. .EXAMPLE C:\PS> Get-VM "*win*" | Get-VMToolsInstallLastError @@ -144,7 +144,7 @@ Function Get-VMToolsInstallLastError { Retrieves the last VMTools installation error code of virtual machines which run on the "MyESXiHostName" ESXi host. .NOTES - This cmdlet assumes that you are connected to at least one vCenter Server system. + This advanced function assumes that you are connected to at least one vCenter Server system. .NOTES Author : Daoyuan Wang @@ -171,7 +171,7 @@ Function Get-VMToolsInstallLastError { Process { $result = @() foreach ($_ in $VM) { - $errorCodeInfo = $_.ExtensionData.Config.ExtraConfig.GetEnumerator() | where {$_.Key -eq "guestinfo.toolsInstallErrCode"} + $errorCodeInfo = $_.ExtensionData.Config.ExtraConfig.GetEnumerator() | Where-Object {$_.Key -eq "guestinfo.toolsInstallErrCode"} $info = New-Object PSObject $info | Add-Member -type NoteProperty -name VmName -value $_.Name @@ -186,10 +186,10 @@ Function Get-VMToolsInstallLastError { Function Get-VMToolsGuestInfo { <# .SYNOPSIS - This cmdlet retrieves the guest info of specified virtual machines. + This advanced function retrieves the guest info of specified virtual machines. .DESCRIPTION - This cmdlet retrieves the guest info such as HostName, IP, ToolsStatus, ToolsVersion, + This advanced function retrieves the guest info such as HostName, IP, ToolsStatus, ToolsVersion, ToolsInstallType and GuestFamily of specified virtual machines. .PARAMETER VM @@ -200,7 +200,7 @@ Function Get-VMToolsGuestInfo { C:\PS> $VCServer = Connect-VIServer -Server -User -Password C:\PS> Get-VM -Server $VCServer | Get-VMToolsGuestInfo - Retrieves guest info of all virtual machines which run in the $VCServer vCetner Server. + Retrieves guest info of all virtual machines which run in the $VCServer vCenter Server. .EXAMPLE C:\PS> Get-VM "*win*" | Get-VMToolsGuestInfo @@ -236,7 +236,7 @@ Function Get-VMToolsGuestInfo { Retrieves guest info of virtual machines which run on the "MyESXiHostName" ESXi host. .NOTES - This cmdlet assumes that you are connected to at least one vCenter Server system. + This advanced function assumes that you are connected to at least one vCenter Server system. .NOTES Author : Daoyuan Wang @@ -261,7 +261,7 @@ Function Get-VMToolsGuestInfo { ) Process { - Get-VM $VM | Select Name, @{Name="HostName"; Expression={$_.Guest.HostName}}, + Get-VM $VM | Select-Object Name, @{Name="HostName"; Expression={$_.Guest.HostName}}, @{Name="IP"; Expression={$_.Guest.ExtensionData.IpAddress}}, @{Name="ToolsStatus"; Expression={$_.Guest.ExtensionData.ToolsStatus}}, @{Name="ToolsVersion"; Expression={$_.Guest.ToolsVersion}}, @@ -274,10 +274,10 @@ Function Get-VMToolsGuestInfo { Function Get-VMByToolsInfo { <# .SYNOPSIS - This cmdlet retrieves the virtual machines with specified VMTools info. + This advanced function retrieves the virtual machines with specified VMTools info. .DESCRIPTION - This cmdlet retrieves the virtual machines with specified VMTools version, + This advanced function retrieves the virtual machines with specified VMTools version, running status or version status. .PARAMETER VM @@ -297,7 +297,7 @@ Function Get-VMByToolsInfo { C:\PS> $VCServer = Connect-VIServer -Server -User -Password C:\PS> Get-VM -Server $VCServer | Get-VMByToolsInfo - Retrieves the virtual machines with VMTools not running in vCetner Server $VCServer. + Retrieves the virtual machines with VMTools not running in vCenter Server $VCServer. .EXAMPLE C:\PS> Get-VM | Get-VMByToolsInfo -ToolsRunningStatus guestToolsNotRunning @@ -328,7 +328,7 @@ Function Get-VMByToolsInfo { Retrieves the virtual machines with VMTools that need to upgrade on the "MyESXiHostName" ESXi host. .NOTES - This cmdlet assumes that you are connected to at least one vCenter Server system. + This advanced function assumes that you are connected to at least one vCenter Server system. .NOTES Author : Daoyuan Wang @@ -361,9 +361,9 @@ Function Get-VMByToolsInfo { [String] $ToolsRunningStatus, [Parameter(Mandatory=$false)] - [ValidateSet("guestToolsNotInstalled", - "guestToolsNeedUpgrade", - "guestToolsCurrent", + [ValidateSet("guestToolsNotInstalled", + "guestToolsNeedUpgrade", + "guestToolsCurrent", "guestToolsUnmanaged")] [String] $ToolsVersionStatus ) @@ -376,65 +376,60 @@ Function Get-VMByToolsInfo { } if ($ToolsVersion) { - $vmList = $vmList | Where {$_.Guest.ToolsVersion -like $ToolsVersion} + $vmList = $vmList | Where-Object {$_.Guest.ToolsVersion -like $ToolsVersion} } if ($ToolsRunningStatus) { - $vmList = $vmList | Where {$_.Guest.ExtensionData.ToolsRunningStatus -eq $ToolsRunningStatus} + $vmList = $vmList | Where-Object {$_.Guest.ExtensionData.ToolsRunningStatus -eq $ToolsRunningStatus} } if ($ToolsVersionStatus) { - $vmList = $vmList | Where {$_.Guest.ExtensionData.ToolsVersionStatus -eq $ToolsVersionStatus} + $vmList = $vmList | Where-Object {$_.Guest.ExtensionData.ToolsVersionStatus -eq $ToolsVersionStatus} } $vmList } } -Function Set-VMToolsUpgradePolicy { +Function Get-VMToolsUpgradePolicy { <# .SYNOPSIS - This cmdlet sets the VMTool's upgrade policy to "upgradeAtPowerCycle". + This advanced function retrieves the VMTools upgrade policy info of specified virtual machines. .DESCRIPTION - This cmdlet sets the VMTool's upgrade policy to "upgradeAtPowerCycle" of specified virtual machines. + This advanced function retrieves the VMTools upgrade policy info of specified virtual machines. .PARAMETER VM - Specifies the virtual machines which you want to set the VMTool's upgrade policy of. + Specifies the virtual machines which you want to query VMTools status of. .EXAMPLE - C:\PS> Import-Module .\VMToolsManagement.psm1 - C:\PS> $VCServer = Connect-VIServer -Server -User -Password - C:\PS> Get-VM -Server $VCServer | Set-VMToolsUpgradePolicy - - Sets VMTool's upgrade policy to "upgradeAtPowerCycle" of all virtual machines in the $VCServer vCetner Server. + C:\PS> Get-VM "*rhel*" | Get-VMToolsUpgradePolicy + Name VMToolsUpgradePolicy + ------ ---------------------- + 111394-RHEL-6.8-0 manual + 111394-RHEL-6.8-1 manual + 111393-RHEL-Server-7.2 upgradeAtPowerCycle + Retrieves VMTools upgrade policy info of virtual machines with name containing "rhel". .EXAMPLE - C:\PS> Get-VM "*win*" | Set-VMToolsUpgradePolicy - - Sets VMTool's upgrade policy to "upgradeAtPowerCycle" of virtual machines with name containing "win". + C:\PS> Get-VM -Location "MyClusterName" | Get-VMToolsUpgradePolicy + Retrieves VMTools upgrade policy info from virtual machines which run in the "MyClusterName" cluster. .EXAMPLE - C:\PS> Get-VM -Location "MyClusterName" | Set-VMToolsUpgradePolicy - - Sets VMTool's upgrade policy to "upgradeAtPowerCycle" of virtual machines in the "MyClusterName" cluster. - -.EXAMPLE - C:\PS> Get-VMHost "MyESXiHostName" | Get-VM | Set-VMToolsUpgradePolicy - - Sets VMTool's upgrade policy to "upgradeAtPowerCycle" of virtual machines on the "MyESXiHostName" ESXi host. + C:\PS> Get-VMHost "MyESXiHostName" | Get-VM | Get-VMToolsUpgradePolicy + Retrieves VMTools upgrade policyinfo of virtual machines which run on the "MyESXiHostName" ESXi host. .NOTES - This cmdlet assumes that you are connected to at least one vCenter Server system. + This advanced function assumes that you are connected to at least one vCenter Server system. .NOTES - Author : Daoyuan Wang - Author email : daoyuanw@vmware.com + Author : Kyle Ruddy + Author email : kmruddy@gmail.com Version : 1.0 ==========Tested Against Environment========== - VMware vSphere Hypervisor(ESXi) Version : 6.5 (build 4564106) - VMware vCenter Server Version : 6.5 (build 4602587) - PowerCLI Version : PowerCLI 6.5 (build 4624819) + VMware vSphere Hypervisor(ESXi) Version : 6.5 (build 7388607) + VMware vCenter Server Version : 6.5 (build 7312210) + PowerCLI Version : PowerCLI 6.5 (build 7155375) PowerShell Version : 5.1 #> @@ -448,8 +443,81 @@ Function Set-VMToolsUpgradePolicy { [ValidateNotNullOrEmpty()] [VMware.VimAutomation.ViCore.Types.V1.Inventory.VirtualMachine[]] $VM ) + + Process { + + Get-VM $VM | Select-Object Name, @{Name="VMToolsUpgradePolicy"; Expression={$_.ExtensionData.Config.Tools.ToolsUpgradePolicy}} + + } + +} + +Function Set-VMToolsUpgradePolicy { +<# +.SYNOPSIS + This advanced function sets the VMTool's upgrade policy to either "manual" or "upgradeAtPowerCycle". + +.DESCRIPTION + This advanced function sets the VMTool's upgrade policy to either "manual" or "upgradeAtPowerCycle" of specified virtual machines. + +.PARAMETER VM + Specifies the virtual machines which you want to set the VMTool's upgrade policy of. + +.EXAMPLE + C:\PS> Import-Module .\VMToolsManagement.psm1 + C:\PS> $VCServer = Connect-VIServer -Server -User -Password + C:\PS> Get-VM -Server $VCServer | Set-VMToolsUpgradePolicy -UpgradePolicy manual + + Sets VMTool's upgrade policy to "manual" of all virtual machines in the $VCServer vCenter Server. + +.EXAMPLE + C:\PS> Get-VM "*win*" | Set-VMToolsUpgradePolicy -UpgradePolicy upgradeAtPowerCycle + + Sets VMTool's upgrade policy to "upgradeAtPowerCycle" of virtual machines with name containing "win". + +.EXAMPLE + C:\PS> Get-VM -Location "MyClusterName" | Set-VMToolsUpgradePolicy -UpgradePolicy upgradeAtPowerCycle + + Sets VMTool's upgrade policy to "upgradeAtPowerCycle" of virtual machines in the "MyClusterName" cluster. + +.EXAMPLE + C:\PS> Get-VMHost "MyESXiHostName" | Get-VM | Set-VMToolsUpgradePolicy -UpgradePolicy manual + + Sets VMTool's upgrade policy to "manual" of virtual machines on the "MyESXiHostName" ESXi host. + +.NOTES + This advanced function assumes that you are connected to at least one vCenter Server system. + +.NOTES + Author : Daoyuan Wang + Author email : daoyuanw@vmware.com + Version : 1.1 + Update Author : Kyle Ruddy + Update email : kmruddy@gmail.com + ==========Tested Against Environment========== + VMware vSphere Hypervisor(ESXi) Version : 6.5 (build 4564106)(build 7388607) + VMware vCenter Server Version : 6.5 (build 4602587)(build 7312210) + PowerCLI Version : PowerCLI 6.5 (build 4624819)(build 7155375) + PowerShell Version : 5.1 +#> + + [CmdletBinding(SupportsShouldProcess)] + + Param ( + [Parameter(Mandatory=$true, + ValueFromPipeLine = $true, + ValueFromPipelinebyPropertyName=$True, + Position = 0)] + [ValidateNotNullOrEmpty()] + [VMware.VimAutomation.ViCore.Types.V1.Inventory.VirtualMachine[]] $VM, + + [Parameter(Mandatory=$false, + Position = 1)] + [ValidateSet("upgradeAtPowerCycle", + "manual")] + [String] $UpgradePolicy + ) Begin { - $UpgradePolicy = "upgradeAtPowerCycle" $vmConfigSpec = New-Object VMware.Vim.VirtualMachineConfigSpec $vmConfigSpec.Tools = New-Object VMware.Vim.ToolsConfigInfo $vmConfigSpec.Tools.ToolsUpgradePolicy = $UpgradePolicy @@ -463,6 +531,7 @@ Function Set-VMToolsUpgradePolicy { if ($vmView.Config.Tools.ToolsUpgradePolicy -ne $UpgradePolicy) { Write-Verbose "Applying 'upgradeAtPowerCycle' setting to $($_.Name)..." $vmView.ReconfigVM($vmConfigSpec) + Get-VMToolsUpgradePolicy -VM $_ } } } @@ -471,10 +540,10 @@ Function Set-VMToolsUpgradePolicy { Function Invoke-VMToolsListProcessInVM { <# .Synopsis - This cmdlet lists the processes in the virtual machine. + This advanced function lists the processes in the virtual machine. .Description - This cmdlet lists the running processes in the virtual machine. + This advanced function lists the running processes in the virtual machine. .PARAMETER VM Specifies the virtual machine which you want to list the processes of. @@ -503,7 +572,7 @@ Function Invoke-VMToolsListProcessInVM { List the processes in the "MyVMName" VM. .NOTES - This cmdlet lists processes in the guest OS of virtual machine. + This advanced function lists processes in the guest OS of virtual machine. A VMTools should already be running in the guest OS. .NOTES @@ -559,10 +628,10 @@ Function Invoke-VMToolsListProcessInVM { Function Update-VMToolsImageLocation { <# .Synopsis - This cmdlet updates the link /productLocker in ESXi host. + This advanced function updates the link /productLocker in ESXi host. .Description - This cmdlet updates the link /productLocker in ESXi host directly to avoid host reboot. + This advanced function updates the link /productLocker in ESXi host directly to avoid host reboot. .Parameter VMHost Specifies the ESXi host on which you want to update the /productLocker link. @@ -574,7 +643,7 @@ Function Update-VMToolsImageLocation { Specifies the password you want to use for authenticating with the ESXi host. .Parameter ImageLocation - Specifies the new image location where you want /producterLocker to link. + Specifies the new image location Where-Object you want /producterLocker to link. .Example C:\PS> Import-Module .\VMToolsManagement.psm1 @@ -586,9 +655,9 @@ Function Update-VMToolsImageLocation { Update the link /producterLocker on $SampleHost to point to '/locker/packages/6.5.0/'. .NOTES - This cmdlet connects to ESXi host to execute shell command directly. + This advanced function connects to ESXi host to execute shell command directly. Make sure the SSH service on ESXi host is enabled, and a SSH library(Posh-SSH or SSH-Sessions etc.) - for powershell is already installed on client where you call This cmdlet. + for powershell is already installed on client Where-Object you call this advanced function. You can instal Posh-SSH by executing: iex (New-Object Net.WebClient).DownloadString("https://gist.github.com/darkoperator/6152630/raw/c67de4f7cd780ba367cccbc2593f38d18ce6df89/instposhsshdev") For SSH-Sessions installation and usage, please refer to @@ -628,7 +697,7 @@ Function Update-VMToolsImageLocation { Process { if (-not (Get-Command New-SSHSession)) { - Throw "This cmdlet depends on SSH library. Please ensure a SSH library is already installed!" + Throw "This advanced function depends on SSH library. Please ensure a SSH library is already installed!" } $password = new-object System.Security.SecureString @@ -656,18 +725,21 @@ Function Update-VMToolsImageLocation { } } -Function Update-VMToolsConfInVM { +Function Set-VMToolsConfInVM { <# .Synopsis - This cmdlet updates the tools.conf content in guest OS. + This advanced function sets the tools.conf content in guest OS. .Description - This cmdlet copies the tools.conf in gueset OS of virtual machine to localhost, - then updates it locally by setting "vmtoolsd.level = info" and copies it back to the guest OS. + This advanced function copies the tools.conf in gueset OS of virtual machine to localhost, + then sets it locally by setting "vmtoolsd.level" to a valid level and copies it back to the guest OS. .PARAMETER VM Specifies the virtual machine to update. +.PARAMETER LogLevel + Specifies the desired log level to log. + .Parameter GuestUser Specifies the user name you want to use for authenticating with the guest OS. @@ -684,16 +756,18 @@ Function Update-VMToolsConfInVM { Updates the tools.conf in $SampleVM, changes the vmtoolsd log level to info ("vmtoolsd.level = info") for example. .NOTES - This cmdlet updates the tools.conf in guest OS. A VMTools should already be running in the guest OS. + This advanced function updates the tools.conf in guest OS. A VMTools should already be running in the guest OS. .NOTES Author : Daoyuan Wang Author email : daoyuanw@vmware.com - Version : 1.0 + Version : 1.1 + Update Author : Kyle Ruddy + Update email : kmruddy@gmail.com ==========Tested Against Environment========== - VMware vSphere Hypervisor(ESXi) Version : 6.5 (build 4564106) - VMware vCenter Server Version : 6.5 (build 4602587) - PowerCLI Version : PowerCLI 6.5 (build 4624819) + VMware vSphere Hypervisor(ESXi) Version : 6.5 (build 4564106)(build 7388607) + VMware vCenter Server Version : 6.5 (build 4602587)(build 7312210) + PowerCLI Version : PowerCLI 6.5 (build 4624819)(build 7155375) PowerShell Version : 5.1 #> @@ -707,6 +781,17 @@ Function Update-VMToolsConfInVM { [ValidateNotNullOrEmpty()] [VMware.VimAutomation.ViCore.Types.V1.Inventory.VirtualMachine] $VM, + [Parameter(Mandatory=$true, + Position = 1)] + [ValidateSet("none", + "critical", + "error", + "warning", + "message", + "info", + "debug")] + [String] $LogLevel, + [Parameter(Mandatory=$true)] [String] $GuestUser, @@ -756,7 +841,7 @@ Function Update-VMToolsConfInVM { # Updates tools.conf by setting vmtoolsd.level = info, just for example. ############################################################################# $confContent = Get-Content $localToolsConfFile - $updatedContent = "vmtoolsd.level = info" + $updatedContent = "vmtoolsd.level = $LogLevel" Write-Verbose "Editing tools.conf (set 'vmtoolsd.level = info' for example)..." if ($confContent -match "vmtoolsd\.level") { @@ -775,19 +860,23 @@ Function Update-VMToolsConfInVM { -GuestUser $GuestUser -GuestPassword $GuestPassword -Force -ErrorAction:Stop } catch { Write-Error "Failed to update tools.conf of $VM" + Write-Verbose "Removing the local tools configuration file" + Remove-Item $localToolsConfFile return } Write-Host "The tools.conf updated in $VM successfully." -ForegroundColor Green + Write-Verbose "Removing the local tools configuration file" + Remove-Item $localToolsConfFile } } Function Invoke-VMToolsVIBInstall { <# .SYNOPSIS - This cmdlet installs VMTool VIB in ESXi hosts. + This advanced function installs VMTool VIB in ESXi hosts. .DESCRIPTION - This cmdlet installs VMTool VIB in specified ESXi hosts. + This advanced function installs VMTool VIB in specified ESXi hosts. .PARAMETER VMHost Specifies the ESXi hosts which you want to install VMTool VIB in. @@ -816,7 +905,7 @@ Function Invoke-VMToolsVIBInstall { Installs VMTool VIB in ESXi host of the "MyClusterName" cluster. .NOTES - This cmdlet assumes that you are connected to at least one vCenter Server system. + This advanced function assumes that you are connected to at least one vCenter Server system. .NOTES Author : Daoyuan Wang @@ -846,7 +935,7 @@ Function Invoke-VMToolsVIBInstall { foreach ($_ in $VMHost) { $esxcli = Get-EsxCLI -VMHost $_ -V2 - $result = $esxcli.software.vib.list.Invoke() | where {$_.name -match 'tools'} + $result = $esxcli.software.vib.list.Invoke() | Where-Object {$_.name -match 'tools'} Write-Verbose "Existing tools VIB on $_ before installing: $($result.Name)_$($result.Version)" # Install VIBs @@ -861,7 +950,7 @@ Function Invoke-VMToolsVIBInstall { Write-Error "Failed to install VMTools VIB package!" } else { Write-Verbose $result.Message - $result = $esxcli.software.vib.list.Invoke() | where {$_.name -match 'tools'} + $result = $esxcli.software.vib.list.Invoke() | Where-Object {$_.name -match 'tools'} Write-Verbose "Tools VIB on $_ after installing: $($result.Name)_$($result.Version)" Write-Host "VMTools VIB package installed on $_ successfully." -ForegroundColor Green } @@ -872,10 +961,10 @@ Function Invoke-VMToolsVIBInstall { Function Invoke-VMToolsUpgradeInVMs { <# .SYNOPSIS - This cmdlet upgrades VMTools to the version bundled by ESXi host. + This advanced function upgrades VMTools to the version bundled by ESXi host. .DESCRIPTION - This cmdlet upgrades VMTools of specified virtual machines to the version + This advanced function upgrades VMTools of specified virtual machines to the version bundled by ESXi host. You can also specify the number of virtual machines to upgrade in parallel. @@ -896,7 +985,7 @@ Function Invoke-VMToolsUpgradeInVMs { C:\PS> $VCServer = Connect-VIServer -Server -User -Password C:\PS> Get-VM -Server $VCServer | Invoke-VMToolsUpgradeInVMs -MaxParallelUpgrades 5 - Upgrades VMTools of all virtual machines in the $VCServer vCetner Server, 5 at a time in parallel. + Upgrades VMTools of all virtual machines in the $VCServer vCenter Server, 5 at a time in parallel. .EXAMPLE C:\PS> Get-VM | Invoke-VMToolsUpgradeInVMs -GuestOSType windows -MaxParallelUpgrades 1 | ft -Autosize @@ -929,7 +1018,7 @@ Function Invoke-VMToolsUpgradeInVMs { Upgrades VMTools of virtual machines on the "MyESXiHostName" ESXi host, 5 at a time. .NOTES - This cmdlet assumes an old VMTools is already running in the virtual machine. + This advanced function assumes an old VMTools is already running in the virtual machine. .NOTES Author : Daoyuan Wang @@ -1026,7 +1115,7 @@ Function Invoke-VMToolsUpgradeInVMs { # Load PowerCLI module and connect to VCServer, as child thread environment is independent with parent if(-not $global:DefaultVIServer) { $moduleName = "vmware.vimautomation.core" - if(-not (Get-Module | Where {$_.name -eq $moduleName})) { + if(-not (Get-Module | Where-Object {$_.name -eq $moduleName})) { try { Import-Module $moduleName -ErrorAction SilentlyContinue | Out-Null } @@ -1130,7 +1219,7 @@ Function Invoke-VMToolsUpgradeInVMs { End { #Verify all threads completed - while (($jobs | Where {$_.Handle.iscompleted -ne ‘Completed’}).Count -gt 0) { + while (($jobs | Where-Object {$_.Handle.iscompleted -ne ‘Completed’}).Count -gt 0) { Start-Sleep -Seconds 5 } @@ -1146,4 +1235,4 @@ Function Invoke-VMToolsUpgradeInVMs { } } -Export-ModuleMember *-* \ No newline at end of file +Export-ModuleMember *-* From 02286dbe53f7196003c4ab0ad71c3cf139dd204c Mon Sep 17 00:00:00 2001 From: Kyle Ruddy Date: Tue, 9 Jan 2018 14:55:28 -0500 Subject: [PATCH 23/29] Update VMToolsManagement.psm1 Update the quotes on line 1222 so that the module import no longer errors out. --- Modules/VMToolsManagement/VMToolsManagement.psm1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Modules/VMToolsManagement/VMToolsManagement.psm1 b/Modules/VMToolsManagement/VMToolsManagement.psm1 index 335476d..df6e2e8 100644 --- a/Modules/VMToolsManagement/VMToolsManagement.psm1 +++ b/Modules/VMToolsManagement/VMToolsManagement.psm1 @@ -1219,7 +1219,7 @@ Function Invoke-VMToolsUpgradeInVMs { End { #Verify all threads completed - while (($jobs | Where-Object {$_.Handle.iscompleted -ne ‘Completed’}).Count -gt 0) { + while (($jobs | Where-Object {$_.Handle.iscompleted -ne "Completed"}).Count -gt 0) { Start-Sleep -Seconds 5 } From 5bee9abf629f2e16eda72dda891fa8b2eac14f88 Mon Sep 17 00:00:00 2001 From: cloudcowboyco Date: Thu, 11 Jan 2018 15:57:17 -0500 Subject: [PATCH 24/29] Fixing spelling errors and grammar issues --- README.md | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/README.md b/README.md index 7d2825c..86afe3e 100644 --- a/README.md +++ b/README.md @@ -59,15 +59,15 @@ The repository has been provided to allow the community to share resources that 1. Browse to the appropriate section (example: Scripts) 2. Select the “Create new file” button 3. On the new page, enter a file name, enter the resource’s information -4. Within the “Commit new file” area, enter the title and description, then select “Create a new branch for this commit…” and enter a sensical branch name +4. Within the “Commit new file” area, enter the title and description, then select “Create a new branch for this commit…” and enter a sensible branch name 5. Click “Propose new file” 6. On the “Open a pull request” page, click “Create pull request” #### GitHub - Upload files Option 1. Browse to the appropriate section (example: Modules) 2. Select the “Upload files” button -3. On the new page, drag or choose the files to add -4. Within the “Commit changes” area, enter the title and description, then select “Create a new branch for this commit…” and enter a sensical branch name +3. On the new page, drag or choose the files to add +4. Within the “Commit changes” area, enter the title and description, then select “Create a new branch for this commit…” and enter a sensible branch name 5. Click “Propose new file” 6. On the “Open a pull request” page, click “Create pull request” @@ -88,7 +88,7 @@ The following information must be included with each submitted scripting resourc #### Note Placement Examples: Script: Top few lines Module: Module manifest - + #### Required Script Note Example: `<#` `Script name: script_name.ps1` @@ -126,7 +126,7 @@ The following information should be included when possible. Inclusion of informa This section describes guidelines put in place to maintain a standard of quality while also promoting broader contribution. ### General Best Practices ### Resource Naming -* Give the resource a name that is indicitive of the actions and/or results of its running +* Give the resource a name that is indicative of the actions and/or results of its running ### Fault Handling * Read and apply the following basic fault handling where applicable: Microsoft’s Hey, Scripting Guy! Blog: https://blogs.technet.microsoft.com/heyscriptingguy/2014/07/09/handling-errors-the-powershell-way/ @@ -138,7 +138,7 @@ This section describes guidelines put in place to maintain a standard of quality * Avoid changing any global variables ### Help Information -* All resources should have inline documentation. +* All resources should have inline documentation. ### Scripts * The script should be easy to read and understand @@ -149,27 +149,27 @@ This section describes guidelines put in place to maintain a standard of quality * Use only standard verbs ### Security -* Usage of PowerShell’s strict mode is preferred, but not required. +* Usage of PowerShell’s strict mode is preferred, but not required. * Remove any information related to one’s own environment (examples: Passwords, DNS/IP Addresses, custom user credentials, etc) ## Resource Maintenance ### Maintenance Ownership -Ownership of any and all submitted resources are maintained by the submitter. This ownership also includes maintenance of any and all submitted resources. +Ownership of any and all submitted resources are maintained by the submitter. This ownership also includes maintenance of any and all submitted resources. ### Filing Issues -Any bugs or other issues should be filed within GitHub by way of the repository’s Issue Tracker. -### Resolving Issues -Any community member can resolve issues within the repository, however only the owner or a board member can approve the update. Once approved, assuming the resolution involves a pull request, only a board member will be able to merge and close the request. +Any bugs or other issues should be filed within GitHub by way of the repository’s Issue Tracker. +### Resolving Issues +Any community member can resolve issues within the repository, however only the owner or a board member can approve the update. Once approved, assuming the resolution involves a pull request, only a board member will be able to merge and close the request. ## Additional Resources ### Discussions Join in on the discussion within the VMware Code Slack team's PowerCLI channel: ### VMware Sample Exchange -It is highly recommened to add any and all submitted resources to the VMware Sample Exchange: - +It is highly recommended to add any and all submitted resources to the VMware Sample Exchange: + Sample Exchange can be allowed to access your GitHub resources, by way of a linking process, where they can be indexed and searched by the community. There are VMware social media accounts which will advertise resources posted to the site and there's no additional accounts needed, as the VMware Sample Exchange uses MyVMware credentials. ## VMWARE TECHNOLOGY PREVIEW LICENSE AGREEMENT -The VMware Technnology Preview License Agreement: +The VMware Technology Preview License Agreement: # Repository Administrator Resources ## Table of Contents @@ -180,7 +180,7 @@ The VMware Technnology Preview License Agreement: Date: Thu, 18 Jan 2018 08:37:38 -0800 Subject: [PATCH 25/29] Add PowerCLI_FixNestedFolders.ps1 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add script to help remove the nested version folders when moving PowerCLI module folders from systems with PoSh 5.x to 4.0/3.0 systems that can’t properly understand those versioned folders. More info: https://blogs.vmware.com/PowerCLI/2018/01/powercli-offline-installation- walkthrough.html --- Scripts/PowerCLI_FixNestedFolders.ps1 | 96 +++++++++++++++++++++++++++ 1 file changed, 96 insertions(+) create mode 100644 Scripts/PowerCLI_FixNestedFolders.ps1 diff --git a/Scripts/PowerCLI_FixNestedFolders.ps1 b/Scripts/PowerCLI_FixNestedFolders.ps1 new file mode 100644 index 0000000..a4e8afe --- /dev/null +++ b/Scripts/PowerCLI_FixNestedFolders.ps1 @@ -0,0 +1,96 @@ +<# +Script name: PowerCLI_FixNestedFolders.ps1 +Created on: 01/11/2018 +Author: Kyle Ruddy, @kmruddy, thatcouldbeaproblem.com +Description: The purpose of the script is to remove the nested Version based folders when using Powercli on systems using older versions of PowerShell +Dependencies: None known + +===Tested Against Environment==== +PowerCLI Version: PowerCLI 6.5.4 +PowerShell Version: 5.1, 4.0 +OS Version: Server 2016, Server 2012 R2 +#> + +# Variable used to store where the PowerCLI module folders exist +$pcliFolder = @() + +# Variable used to store the current PSModulePath locations +$downloadDir = $env:PSModulePath.Split(';') + +# Loop to detect PowerCLI module folders in any of the PSModulePath locations +foreach ($possPath in $downloadDir) { + + # Verifying the PSModulePath location exists + if ((Test-Path -Path $possPath) -eq $true) { + + # Searching for folders with the name of 'VMware.*' + $tempFolder = Get-ChildItem -Path $possPath -Name "VMware.*" + + # If a VMware.* module folder is found, the full path is added to the pcliFolder variable + if ($tempFolder) { + + foreach ($moduleName in $tempFolder) { + $pcliFolder += $possPath + "\" + $moduleName + } + } + + } +} + +# Verifying that there were PowerCLI module folders found +if ($pcliFolder) { + + # Looping through each of the found PowerCLI module folders + foreach ($dir in $pcliFolder) { + + # Variable to be used if there are several PowerCLI module versions available + $historicDir = $null + + # Varibale used to store the PowerCLI module version folder + $tempDir = Get-ChildItem -Path $dir + + # Verifying whether or not there are several PowerCLI module versions available by checking for a type of 'array' + if ($tempDir -is [array]) { + + # Variable used to store the current folder structure + $historicDir = $tempDir + # Updating the tempDir variable to only contain the newest PowerCLI module version folder + $tempDir = $tempDir | Sort-Object Name -Descending | select-Object -First 1 + + } + + # Verifying the child item is indeed a folder + if ($tempDir.GetType().Name -eq "DirectoryInfo") { + + # Obtaining the child objects of the PowerCLI module version folder and copying them to the parent folder + $tempDir | Get-ChildItem | Copy-Item -Destination $dir -ErrorAction Stop + + # Checking for any nested folders within the PowerCLI module version folder + if ($tempDir | Get-ChildItem -Directory) { + + # Obtaining and storing the child items to a variable, then copying the items to the parent folder's nested folder + $nestFolder = $tempDir | Get-ChildItem -Directory + foreach ($nestDir in $nestFolder) { + $nestDir | Get-ChildItem | Copy-Item -Destination ($dir + "\" + $nestDir.Name) -ErrorAction Stop + } + + } + + # Detecting whether the historicDir variable was used + if ($historicDir) { + + # Removing any of the former, no longer needed, directory structure + $historicDir | Remove-Item -Recurse -Force + + } + else { + + # Removing any of the former, no longer needed, directory structure + $tempDir | Remove-Item -Recurse -Force + + } + } + } + +} +else {Write-Host 'No PowerCLI module folders founds in the $PSModulePath directories.'} \ No newline at end of file From 61aead2685b8af74075cbdc3dc4b74ee9bb1350d Mon Sep 17 00:00:00 2001 From: Ben Meadowcroft Date: Tue, 30 Jan 2018 21:03:35 -0800 Subject: [PATCH 26/29] Initial commit to Examples of SRM-Cmdlets --- Modules/SRM/.gitattributes | 1 + Modules/SRM/.gitignore | 1 + Modules/SRM/Examples/ReportConfiguration.ps1 | 167 ++++++ Modules/SRM/Examples/SrmTagging.ps1 | 34 ++ Modules/SRM/LICENSE.txt | 74 +++ Modules/SRM/Meadowcroft.Srm.Protection.ps1 | 422 ++++++++++++++ Modules/SRM/Meadowcroft.Srm.Recovery.ps1 | 556 +++++++++++++++++++ Modules/SRM/Meadowcroft.Srm.Storage.ps1 | 24 + Modules/SRM/Meadowcroft.Srm.psd1 | 92 +++ Modules/SRM/Meadowcroft.Srm.psm1 | 148 +++++ Modules/SRM/NOTICE.txt | 7 + Modules/SRM/README.md | 81 +++ 12 files changed, 1607 insertions(+) create mode 100644 Modules/SRM/.gitattributes create mode 100644 Modules/SRM/.gitignore create mode 100644 Modules/SRM/Examples/ReportConfiguration.ps1 create mode 100644 Modules/SRM/Examples/SrmTagging.ps1 create mode 100644 Modules/SRM/LICENSE.txt create mode 100644 Modules/SRM/Meadowcroft.Srm.Protection.ps1 create mode 100644 Modules/SRM/Meadowcroft.Srm.Recovery.ps1 create mode 100644 Modules/SRM/Meadowcroft.Srm.Storage.ps1 create mode 100644 Modules/SRM/Meadowcroft.Srm.psd1 create mode 100644 Modules/SRM/Meadowcroft.Srm.psm1 create mode 100644 Modules/SRM/NOTICE.txt create mode 100644 Modules/SRM/README.md diff --git a/Modules/SRM/.gitattributes b/Modules/SRM/.gitattributes new file mode 100644 index 0000000..75f1064 --- /dev/null +++ b/Modules/SRM/.gitattributes @@ -0,0 +1 @@ +*.psd1 diff diff --git a/Modules/SRM/.gitignore b/Modules/SRM/.gitignore new file mode 100644 index 0000000..6f66c74 --- /dev/null +++ b/Modules/SRM/.gitignore @@ -0,0 +1 @@ +*.zip \ No newline at end of file diff --git a/Modules/SRM/Examples/ReportConfiguration.ps1 b/Modules/SRM/Examples/ReportConfiguration.ps1 new file mode 100644 index 0000000..f7a8036 --- /dev/null +++ b/Modules/SRM/Examples/ReportConfiguration.ps1 @@ -0,0 +1,167 @@ +# Depends on SRM Helper Methods - https://github.com/benmeadowcroft/SRM-Cmdlets +# It is assumed that the connection to VC and SRM Server have already been made + +Function Get-SrmConfigReportSite { + Param( + [VMware.VimAutomation.Srm.Types.V1.SrmServer] $SrmServer + ) + + Get-SrmServer $SrmServer | + Format-Table -Wrap -AutoSize @{Label="SRM Site Name"; Expression={$_.ExtensionData.GetSiteName()} }, + @{Label="SRM Host"; Expression={$_.Name} }, + @{Label="SRM Port"; Expression={$_.Port} }, + @{Label="Version"; Expression={$_.Version} }, + @{Label="Build"; Expression={$_.Build} }, + @{Label="SRM Peer Site Name"; Expression={$_.ExtensionData.GetPairedSite().Name} } +} + +Function Get-SrmConfigReportPlan { + Param( + [VMware.VimAutomation.Srm.Types.V1.SrmServer] $SrmServer + ) + + Get-SrmRecoveryPlan -SrmServer $SrmServer | %{ + $rp = $_ + $rpinfo = $rp.GetInfo() + $peerState = $rp.GetPeer().State + $pgs = Get-SrmProtectionGroup -RecoveryPlan $rp + $pgnames = $pgs | %{ $_.GetInfo().Name } + + $output = "" | select plan, state, peerState, groups + $output.plan = $rpinfo.Name + $output.state = $rpinfo.State + $output.peerState = $peerState + if ($pgnames) { + $output.groups = [string]::Join(",`r`n", $pgnames) + } else { + $output.groups = "NONE" + } + + $output + } | Format-Table -Wrap -AutoSize @{Label="Recovery Plan Name"; Expression={$_.plan} }, + @{Label="Recovery State"; Expression={$_.state} }, + @{Label="Peer Recovery State"; Expression={$_.peerState} }, + @{Label="Protection Groups"; Expression={$_.groups}} +} + + +Function Get-SrmConfigReportProtectionGroup { + Param( + [VMware.VimAutomation.Srm.Types.V1.SrmServer] $SrmServer + ) + + Get-SrmProtectionGroup -SrmServer $SrmServer | %{ + $pg = $_ + $pginfo = $pg.GetInfo() + $pgstate = $pg.GetProtectionState() + $peerState = $pg.GetPeer().State + $rps = Get-SrmRecoveryPlan -ProtectionGroup $pg + $rpnames = $rps | %{ $_.GetInfo().Name } + + $output = "" | select name, type, state, peerState, plans + $output.name = $pginfo.Name + $output.type = $pginfo.Type + $output.state = $pgstate + $output.peerState = $peerState + if ($rpnames) { + $output.plans = [string]::Join(",`r`n", $rpnames) + } else { + $output.plans = "NONE" + } + + $output + } | Format-Table -Wrap -AutoSize @{Label="Protection Group Name"; Expression={$_.name} }, + @{Label="Type"; Expression={$_.type} }, + @{Label="Protection State"; Expression={$_.state} }, + @{Label="Peer Protection State"; Expression={$_.peerState} }, + @{Label="Recovery Plans"; Expression={$_.plans} } +} + + +Function Get-SrmConfigReportProtectedDatastore { + Param( + [VMware.VimAutomation.Srm.Types.V1.SrmServer] $SrmServer + ) + + Get-SrmProtectionGroup -SrmServer $SrmServer -Type "san" | %{ + $pg = $_ + $pginfo = $pg.GetInfo() + $pds = Get-SrmProtectedDatastore -ProtectionGroup $pg + $pds | %{ + $pd = $_ + $output = "" | select datacenter, group, name, capacity, free + $output.datacenter = $pd.Datacenter.Name + $output.group = $pginfo.Name + $output.name = $pd.Name + $output.capacity = $pd.CapacityGB + $output.free = $pd.FreeSpaceGB + + $output + + } + } | Format-Table -Wrap -AutoSize -GroupBy "datacenter" @{Label="Datastore Name"; Expression={$_.name} }, + @{Label="Capacity GB"; Expression={$_.capacity} }, + @{Label="Free GB"; Expression={$_.free} }, + @{Label="Protection Group"; Expression={$_.group} } +} + + +Function Get-SrmConfigReportProtectedVm { + Param( + [VMware.VimAutomation.Srm.Types.V1.SrmServer] $SrmServer + ) + + $srmversion = Get-SrmServerVersion -SrmServer $SrmServer + $srmMajorVersion, $srmMinorVersion = $srmversion -split "\." + + Get-SrmProtectionGroup -SrmServer $SrmServer | %{ + $pg = $_ + $pginfo = $pg.GetInfo() + $pvms = Get-SrmProtectedVM -ProtectionGroup $pg + $rps = Get-SrmRecoveryPlan -ProtectionGroup $pg + $rpnames = $rps | %{ $_.GetInfo().Name } + $pvms | %{ + $pvm = $_ + if ($srmMajorVersion -ge 6 -or ($srmMajorVersion -eq 5 -and $srmMinorVersion -eq 8)) { + $rs = $rps | Select -First 1 | %{ $_.GetRecoverySettings($pvm.Vm.MoRef) } + } + $output = "" | select group, name, moRef, needsConfiguration, state, plans, priority, finalPowerState, preCallouts, postCallouts + $output.group = $pginfo.Name + $output.name = $pvm.Vm.Name + $output.moRef = $pvm.Vm.MoRef # this is necessary in case we can't retrieve the name when VC is unavailable + $output.needsConfiguration = $pvm.NeedsConfiguration + $output.state = $pvm.State + $output.plans = [string]::Join(",`r`n", $rpnames) + if ($rs) { + $output.priority = $rs.RecoveryPriority + $output.finalPowerState = $rs.FinalPowerState + $output.preCallouts = $rs.PrePowerOnCallouts.Count + $output.postCallouts = $rs.PostPowerOnCallouts.Count + } + $output + + } + } | Format-Table -Wrap -AutoSize @{Label="VM Name"; Expression={$_.name} }, + @{Label="VM MoRef"; Expression={$_.moRef} }, + @{Label="Needs Config"; Expression={$_.needsConfiguration} }, + @{Label="VM Protection State"; Expression={$_.state} }, + @{Label="Protection Group"; Expression={$_.group} }, + @{Label="Recovery Plans"; Expression={$_.plans} }, + @{Label="Recovery Priority"; Expression={$_.priority} }, + @{Label="Final Power State"; Expression={$_.finalPowerState} }, + @{Label="Pre-PowerOn Callouts"; Expression={$_.preCallouts} }, + @{Label="Post-PowerOn Callouts"; Expression={$_.postCallouts} } + +} + +Function Get-SrmConfigReport { + Param( + [VMware.VimAutomation.Srm.Types.V1.SrmServer] $SrmServer + ) + + Get-SrmConfigReportSite -SrmServer $SrmServer + Get-SrmConfigReportPlan -SrmServer $SrmServer + Get-SrmConfigReportProtectionGroup -SrmServer $SrmServer + Get-SrmConfigReportProtectedDatastore -SrmServer $SrmServer + Get-SrmConfigReportProtectedVm -SrmServer $SrmServer +} diff --git a/Modules/SRM/Examples/SrmTagging.ps1 b/Modules/SRM/Examples/SrmTagging.ps1 new file mode 100644 index 0000000..1e33659 --- /dev/null +++ b/Modules/SRM/Examples/SrmTagging.ps1 @@ -0,0 +1,34 @@ +# Depends on SRM Helper Methods - https://github.com/benmeadowcroft/SRM-Cmdlets +# It is assumed that the connections to active VC and SRM Server have already been made + +Import-Module Meadowcroft.SRM -Prefix Srm + +$TagCategoryName = 'Meadowcroft.SRM.VM' +$TagCategoryDescription = 'Tag category for tagging VMs with SRM state' + +# If the tag category doesn't exist, create it and the relevant tags +$TagCategory = Get-TagCategory -Name $TagCategoryName -ErrorAction SilentlyContinue +if (-Not $TagCategory) { + Write-Output "Creating Tag Category $TagCategoryName" + $TagCategory = New-TagCategory -Name $TagCategoryName -Description $TagCategoryDescription -EntityType 'VirtualMachine' + + Write-Output "Creating Tag SrmProtectedVm" + New-Tag -Name 'SrmProtectedVm' -Category $TagCategory -Description "VM protected by VMware SRM" + Write-Output "Creating Tag SrmTestVm" + New-Tag -Name 'SrmTestVm' -Category $TagCategory -Description "Test VM instantiated by VMware SRM" + Write-Output "Creating Tag SrmPlaceholderVm" + New-Tag -Name 'SrmPlaceholderVm' -Category $TagCategory -Description "Placeholder VM used by VMware SRM" +} + +$protectedVmTag = Get-Tag -Name 'SrmProtectedVm' -Category $TagCategory +$testVmTag = Get-Tag -Name 'SrmTestVm' -Category $TagCategory +$placeholderVmTag = Get-Tag -Name 'SrmPlaceholderVm' -Category $TagCategory + +# Assign protected tag to a VM, use ready state to get "local" protected VMs +Get-SrmProtectedVM -State Ready | %{ New-TagAssignment -Tag $protectedVmTag -Entity $(Get-VIObjectByVIView $_.Vm) | Out-Null } + +# Assign test tag to a VM +Get-SrmTestVM | %{ New-TagAssignment -Tag $testVmTag -Entity $_ | Out-Null } + +# Assign placeholder tag to a VM +Get-SrmPlaceholderVM | %{ New-TagAssignment -Tag $placeholderVmTag -Entity $_ | Out-Null } diff --git a/Modules/SRM/LICENSE.txt b/Modules/SRM/LICENSE.txt new file mode 100644 index 0000000..22896f0 --- /dev/null +++ b/Modules/SRM/LICENSE.txt @@ -0,0 +1,74 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + +"License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. + +"Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. + +"Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. + +"You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. + +"Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. + +"Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. + +"Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). + +"Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. + +"Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." + +"Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. + +2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: +(a) You must give any other recipients of the Work or Derivative Works a copy of this License; and +(b) You must cause any modified files to carry prominent notices stating that You changed the files; and +(c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and +(d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. + +You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. + +5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS + +APPENDIX: How to apply the Apache License to your work. + +To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "[]" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied. + + See the License for the specific language governing permissions and + limitations under the License. + + diff --git a/Modules/SRM/Meadowcroft.Srm.Protection.ps1 b/Modules/SRM/Meadowcroft.Srm.Protection.ps1 new file mode 100644 index 0000000..d522cb6 --- /dev/null +++ b/Modules/SRM/Meadowcroft.Srm.Protection.ps1 @@ -0,0 +1,422 @@ +# SRM Helper Methods - https://github.com/benmeadowcroft/SRM-Cmdlets + +<# +.SYNOPSIS +Get the subset of protection groups matching the input criteria + +.PARAMETER Name +Return protection groups matching the specified name + +.PARAMETER Type +Return protection groups matching the specified protection group +type. For SRM 5.0-5.5 this is either 'san' for protection groups +consisting of a set of replicated datastores or 'vr' for vSphere +Replication based protection groups. + +.PARAMETER RecoveryPlan +Return protection groups associated with a particular recovery +plan + +.PARAMETER SrmServer +the SRM server to use for this operation. +#> +Function Get-ProtectionGroup { + [cmdletbinding()] + Param( + [Parameter(position=1)][string] $Name, + [string] $Type, + [Parameter (ValueFromPipeline=$true)][VMware.VimAutomation.Srm.Views.SrmRecoveryPlan[]] $RecoveryPlan, + [VMware.VimAutomation.Srm.Types.V1.SrmServer] $SrmServer + ) + begin { + $api = Get-ServerApiEndpoint -SrmServer $SrmServer + $pgs = @() + } + process { + if ($RecoveryPlan) { + foreach ($rp in $RecoveryPlan) { + $pgs += $RecoveryPlan.GetInfo().ProtectionGroups + } + $pgs = Select_UniqueByMoRef($pgs) + } else { + $pgs += $api.Protection.ListProtectionGroups() + } + } + end { + $pgs | ForEach-Object { + $pg = $_ + $pgi = $pg.GetInfo() + $selected = (-not $Name -or ($Name -eq $pgi.Name)) -and (-not $Type -or ($Type -eq $pgi.Type)) + if ($selected) { + Add-Member -InputObject $pg -MemberType NoteProperty -Name "Name" -Value $pgi.Name + $pg + } + } + } +} + +<# +.SYNOPSIS +Get the subset of protected VMs matching the input criteria + +.PARAMETER Name +Return protected VMs matching the specified name + +.PARAMETER State +Return protected VMs matching the specified state. For protected +VMs on the protected site this is usually 'ready', for +placeholder VMs this is 'shadowing' + +.PARAMETER ProtectionGroup +Return protected VMs associated with particular protection +groups +#> +Function Get-ProtectedVM { + [cmdletbinding()] + Param( + [Parameter(position=1)][string] $Name, + [VMware.VimAutomation.Srm.Views.SrmProtectionGroupProtectionState] $State, + [VMware.VimAutomation.Srm.Views.SrmProtectionGroupProtectionState] $PeerState, + [switch] $ConfiguredOnly, + [switch] $UnconfiguredOnly, + [Parameter (ValueFromPipeline=$true)][VMware.VimAutomation.Srm.Views.SrmProtectionGroup[]] $ProtectionGroup, + [Parameter (ValueFromPipeline=$true)][VMware.VimAutomation.Srm.Views.SrmRecoveryPlan[]] $RecoveryPlan, + [string] $ProtectionGroupName, + [VMware.VimAutomation.Srm.Types.V1.SrmServer] $SrmServer + ) + + if ($null -eq $ProtectionGroup) { + $ProtectionGroup = Get-ProtectionGroup -Name $ProtectionGroupName -RecoveryPlan $RecoveryPlan -SrmServer $SrmServer + } + $ProtectionGroup | ForEach-Object { + $pg = $_ + $pg.ListProtectedVms() | ForEach-Object { + # try and update the view data for the protected VM + try { + $_.Vm.UpdateViewData() + } catch { + Write-Error $_ + } finally { + $_ + } + } | Where-object { -not $Name -or ($Name -eq $_.Vm.Name) } | + where-object { -not $State -or ($State -eq $_.State) } | + where-object { -not $PeerState -or ($PeerState -eq $_.PeerState) } | + where-object { ($ConfiguredOnly -and $_.NeedsConfiguration -eq $false) -or ($UnconfiguredOnly -and $_.NeedsConfiguration -eq $true) -or (-not $ConfiguredOnly -and -not $UnconfiguredOnly) } + } +} + + +<# +.SYNOPSIS +Get the unprotected VMs that are associated with a protection group + +.PARAMETER ProtectionGroup +Return unprotected VMs associated with particular protection +groups. For VR protection groups this is VMs that are associated +with the PG but not configured, For ABR protection groups this is +VMs on replicated datastores associated with the group that are not +configured. +#> +Function Get-UnProtectedVM { + [cmdletbinding()] + Param( + [Parameter (ValueFromPipeline=$true)][VMware.VimAutomation.Srm.Views.SrmProtectionGroup[]] $ProtectionGroup, + [Parameter (ValueFromPipeline=$true)][VMware.VimAutomation.Srm.Views.SrmRecoveryPlan[]] $RecoveryPlan, + [string] $ProtectionGroupName, + [VMware.VimAutomation.Srm.Types.V1.SrmServer] $SrmServer + ) + + if ($null -eq $ProtectionGroup) { + $ProtectionGroup = Get-ProtectionGroup -Name $ProtectionGroupName -RecoveryPlan $RecoveryPlan -SrmServer $SrmServer + } + + $associatedVMs = @() + $protectedVmRefs = @() + + $ProtectionGroup | ForEach-Object { + $pg = $_ + # For VR listAssociatedVms to get list of VMs + if ($pg.GetInfo().Type -eq 'vr') { + $associatedVMs += @($pg.ListAssociatedVms() | Get-VIObjectByVIView) + } + # TODO test this: For ABR get VMs on GetProtectedDatastore + if ($pg.GetInfo().Type -eq 'san') { + $pds = @(Get-ProtectedDatastore -ProtectionGroup $pg) + $pds | ForEach-Object { + $ds = Get-Datastore -id $_.MoRef + $associatedVMs += @(Get-VM -Datastore $ds) + } + } + + # get protected VMs + $protectedVmRefs += @(Get-ProtectedVM -ProtectionGroup $pg | ForEach-Object { $_.Vm.MoRef } | Select-Object -Unique) + } + + # get associated but unprotected VMs + $associatedVMs | Where-Object { $protectedVmRefs -notcontains $_.ExtensionData.MoRef } +} + + +#Untested as I don't have ABR setup in my lab yet +<# +.SYNOPSIS +Get the subset of protected Datastores matching the input criteria + +.PARAMETER ProtectionGroup +Return protected datastores associated with particular protection +groups +#> +Function Get-ProtectedDatastore { + [cmdletbinding()] + Param( + [Parameter (ValueFromPipeline=$true)][VMware.VimAutomation.Srm.Views.SrmProtectionGroup[]] $ProtectionGroup, + [Parameter (ValueFromPipeline=$true)][VMware.VimAutomation.Srm.Views.SrmRecoveryPlan[]] $RecoveryPlan, + [string] $ProtectionGroupName, + [VMware.VimAutomation.Srm.Types.V1.SrmServer] $SrmServer + ) + + if (-not $ProtectionGroup) { + $ProtectionGroup = Get-ProtectionGroup -Name $ProtectionGroupName -RecoveryPlan $RecoveryPlan -SrmServer $SrmServer + } + $ProtectionGroup | ForEach-Object { + $pg = $_ + if ($pg.GetInfo().Type -eq 'san') { # only supported for array based replication datastores + $pg.ListProtectedDatastores() + } + } +} + + +#Untested as I don't have ABR setup in my lab yet +<# +.SYNOPSIS +Get the replicated datastores that aren't associated with a protection group. +#> +Function Get-ReplicatedDatastore { + [cmdletbinding()] + Param( + [VMware.VimAutomation.Srm.Types.V1.SrmServer] $SrmServer + ) + + $api = Get-ServerApiEndpoint -SrmServer $SrmServer + + $api.Protection.ListUnassignedReplicatedDatastores() +} + +<# +.SYNOPSIS +Protect a VM using SRM + +.PARAMETER ProtectionGroup +The protection group that this VM will belong to + +.PARAMETER Vm +The virtual machine to protect +#> +Function Protect-VM { + [cmdletbinding()] + Param( + [Parameter (Mandatory=$true)][VMware.VimAutomation.Srm.Views.SrmProtectionGroup] $ProtectionGroup, + [Parameter (ValueFromPipeline=$true)][VMware.VimAutomation.ViCore.Types.V1.Inventory.VirtualMachine] $Vm, + [Parameter (ValueFromPipeline=$true)][VMware.Vim.VirtualMachine] $VmView + ) + + $moRef = Get_MoRefFromVmObj -Vm $Vm -VmView $VmView + + $pgi = $ProtectionGroup.GetInfo() + #TODO query protection status first + + if ($moRef) { + if ($pgi.Type -eq 'vr') { + $ProtectionGroup.AssociateVms(@($moRef)) + } + $protectionSpec = New-Object VMware.VimAutomation.Srm.Views.SrmProtectionGroupVmProtectionSpec + $protectionSpec.Vm = $moRef + $protectTask = $ProtectionGroup.ProtectVms($protectionSpec) + while(-not $protectTask.IsComplete()) { Start-Sleep -Seconds 1 } + $protectTask.GetResult() + } else { + throw "Can't protect the VM, no MoRef found." + } +} + + +<# +.SYNOPSIS +Unprotect a VM using SRM + +.PARAMETER ProtectionGroup +The protection group that this VM will be removed from + +.PARAMETER Vm +The virtual machine to unprotect +#> +Function Unprotect-VM { + [cmdletbinding()] + Param( + [Parameter (Mandatory=$true)][VMware.VimAutomation.Srm.Views.SrmProtectionGroup] $ProtectionGroup, + [Parameter (ValueFromPipeline=$true)][VMware.VimAutomation.ViCore.Types.V1.Inventory.VirtualMachine] $Vm, + [Parameter (ValueFromPipeline=$true)][VMware.Vim.VirtualMachine] $VmView, + [Parameter (ValueFromPipeline=$true)][VMware.VimAutomation.Srm.Views.SrmProtectionGroupProtectedVm] $ProtectedVm + ) + + $moRef = Get_MoRefFromVmObj -Vm $Vm -VmView $VmView -ProtectedVm $ProtectedVm + + $pgi = $ProtectionGroup.GetInfo() + $protectTask = $ProtectionGroup.UnprotectVms($moRef) + while(-not $protectTask.IsComplete()) { Start-Sleep -Seconds 1 } + if ($pgi.Type -eq 'vr') { + $ProtectionGroup.UnassociateVms(@($moRef)) + } + $protectTask.GetResult() +} + +<# +.SYNOPSIS +Get a protection group folder + +.PARAMETER SrmServer +The SRM Server to query for the protection group folder +#> +Function Get-ProtectionGroupFolder { + [cmdletbinding()] + Param( + [VMware.VimAutomation.Srm.Types.V1.SrmServer] $SrmServer + ) + + $api = Get-ServerApiEndpoint -SrmServer $SrmServer + + $folder = $api.Protection.GetProtectionGroupRootFolder() + + return $folder +} + +<# +.SYNOPSIS +Create a new protection group + +.PARAMETER Name +The name of the protection group + +.PARAMETER Description +Description of the protection group + +.PARAMETER Folder +The protection group folder in which to create the new protection group + +.PARAMETER ArrayReplication +Set if protection group is for replicating VMs using Array based replication + +.PARAMETER vSphereReplication +Set if protection group is for replicating VMs with vSphere Replication + +.PARAMETER VMs +For vSphere Replication based protection, the VMs to add to the replication +group. These should already be replicated. + +.PARAMETER VMViews +For vSphere Replication based protection, the VMs to add to the replication +group. These should already be replicated. + +.PARAMETER SrmServer +The SRM Server to perform the operation against +#> +Function New-ProtectionGroup { + [cmdletbinding(DefaultParameterSetName="VR", SupportsShouldProcess=$True, ConfirmImpact="Medium")] + [OutputType([VMware.VimAutomation.Srm.Views.SrmProtectionGroup])] + Param( + [Parameter (Mandatory=$true)] $Name, + $Description, + [VMware.VimAutomation.Srm.Views.SrmProtectionGroupFolder] $Folder, + [Parameter (ParameterSetName="ABR", Mandatory=$true)][switch] $ArrayReplication, + [Parameter (ValueFromPipeline=$true, ParameterSetName="ABR")][VMware.VimAutomation.ViCore.Types.V1.DatastoreManagement.Datastore[]] $Datastores, + [Parameter (ValueFromPipeline=$true, ParameterSetName="ABR")][VMware.Vim.Datastore[]] $DatastoreViews, + [Parameter (ParameterSetName="VR", Mandatory=$true)][switch] $vSphereReplication, + [Parameter (ValueFromPipeline=$true, ParameterSetName="VR")][VMware.VimAutomation.ViCore.Types.V1.Inventory.VirtualMachine[]] $VMs, + [Parameter (ValueFromPipeline=$true, ParameterSetName="VR")][VMware.Vim.VirtualMachine[]] $VMViews, + [VMware.VimAutomation.Srm.Types.V1.SrmServer] $SrmServer + ) + + $api = Get-ServerApiEndpoint $SrmServer + [VMware.VimAutomation.Srm.Views.SrmCreateProtectionGroupTask] $task = $null + + #get root folder if this wasn't specified as a parameter + if(-not $Folder) { + $Folder = Get-ProtectionGroupFolder -SrmServer $SrmServer + } + + if ($vSphereReplication) { + #create list of managed object references from VM and/or VM view arrays + [VMware.Vim.ManagedObjectReference[]]$moRefs = @() + foreach ($vm in $VMs) { + $moRefs += Get_MoRefFromVmObj -Vm $Vm + } + foreach ($VmView in $VMViews) { + $moRefs += Get_MoRefFromVmObj -VmView $VmView + } + + if ($pscmdlet.ShouldProcess($Name, "New")) { + $task = $api.Protection.CreateHbrProtectionGroup($Folder.MoRef, $Name, $Description, $moRefs) + } + + } elseif ($ArrayReplication) { + #create list of managed object references from VM and/or VM view arrays + $moRefs = @() + foreach ($ds in $Datastores) { + $moRefs += $ds.ExtensionData.MoRef + } + foreach ($DsView in $DatastoreViews) { + $moRefs += $DsView.MoRef + } + + if ($pscmdlet.ShouldProcess($Name, "New")) { + $task = $api.Protection.CreateAbrProtectionGroup($Folder.MoRef, $Name, $Description, $moRefs) + } + + } else { + throw "Undetermined protection group type" + } + + # Complete task + while(-not $task.IsCreateProtectionGroupComplete()) { Start-Sleep -Seconds 1 } + + # Retrieve the protection group, and protect associated VMs + $pg = $task.GetNewProtectionGroup() + if ($pg) { + $unProtectedVMs = Get-UnProtectedVM -ProtectionGroup $pg + $unProtectedVMs | Protect-VM -ProtectionGroup $pg + } + + return $pg +} + + +<# +.SYNOPSIS +Delete a protection group + +.PARAMETER ProtectionGroup +The protection group to remove + +.PARAMETER SrmServer +The SRM Server to perform the operation against +#> +Function Remove-ProtectionGroup { + [cmdletbinding(SupportsShouldProcess=$True, ConfirmImpact="High")] + [OutputType([VMware.VimAutomation.Srm.Views.RemoveProtectionGroupTask])] + Param( + [Parameter (Mandatory=$true, ValueFromPipeline=$true)][VMware.VimAutomation.Srm.Views.SrmProtectionGroup] $ProtectionGroup, + [VMware.VimAutomation.Srm.Types.V1.SrmServer] $SrmServer + ) + + $api = Get-ServerApiEndpoint $SrmServer + [VMware.VimAutomation.Srm.Views.RemoveProtectionGroupTask] $task = $null + + $pginfo = $ProtectionGroup.GetInfo() + if ($pscmdlet.ShouldProcess($pginfo.Name, "Remove")) { + $task = $api.Protection.RemoveProtectionGroup($ProtectionGroup.MoRef) + } + + return $task +} diff --git a/Modules/SRM/Meadowcroft.Srm.Recovery.ps1 b/Modules/SRM/Meadowcroft.Srm.Recovery.ps1 new file mode 100644 index 0000000..1b2eaca --- /dev/null +++ b/Modules/SRM/Meadowcroft.Srm.Recovery.ps1 @@ -0,0 +1,556 @@ +# SRM Helper Methods - https://github.com/benmeadowcroft/SRM-Cmdlets + +<# +.SYNOPSIS +Get the subset of recovery plans matching the input criteria + +.PARAMETER Name +Return recovery plans matching the specified name + +.PARAMETER ProtectionGroup +Return recovery plans associated with particular protection +groups +#> +Function Get-RecoveryPlan { + [cmdletbinding()] + Param( + [Parameter(position=1)][string] $Name, + [Parameter (ValueFromPipeline=$true)][VMware.VimAutomation.Srm.Views.SrmProtectionGroup[]] $ProtectionGroup, + [VMware.VimAutomation.Srm.Types.V1.SrmServer] $SrmServer + ) + + begin { + $api = Get-ServerApiEndpoint -SrmServer $SrmServer + $rps = @() + } + process { + if ($ProtectionGroup) { + foreach ($pg in $ProtectionGroup) { + $rps += $pg.ListRecoveryPlans() + } + $rps = Select_UniqueByMoRef($rps) + } else { + $rps += $api.Recovery.ListPlans() + } + } + end { + $rps | ForEach-Object { + $rp = $_ + $rpi = $rp.GetInfo() + $selected = (-not $Name -or ($Name -eq $rpi.Name)) + if ($selected) { + Add-Member -InputObject $rp -MemberType NoteProperty -Name "Name" -Value $rpi.Name + $rp + } + } + } +} + +<# +.SYNOPSIS +Start a Recovery Plan action like test, recovery, cleanup, etc. + +.PARAMETER RecoveryPlan +The recovery plan to start + +.PARAMETER RecoveryMode +The recovery mode to invoke on the plan. May be one of "Test", "Cleanup", "Failover", "Migrate", "Reprotect" +#> +Function Start-RecoveryPlan { + [cmdletbinding(SupportsShouldProcess=$True, ConfirmImpact="High")] + Param( + [Parameter (Mandatory=$true, ValueFromPipeline=$true, Position=1)][VMware.VimAutomation.Srm.Views.SrmRecoveryPlan] $RecoveryPlan, + [VMware.VimAutomation.Srm.Views.SrmRecoveryPlanRecoveryMode] $RecoveryMode = [VMware.VimAutomation.Srm.Views.SrmRecoveryPlanRecoveryMode]::Test, + [bool] $SyncData = $True + ) + + # Validate with informative error messages + $rpinfo = $RecoveryPlan.GetInfo() + + # Create recovery options + $rpOpt = New-Object VMware.VimAutomation.Srm.Views.SrmRecoveryOptions + $rpOpt.SyncData = $SyncData + + # Prompt the user to confirm they want to execute the action + if ($pscmdlet.ShouldProcess($rpinfo.Name, $RecoveryMode)) { + if ($rpinfo.State -eq 'Protecting') { + throw "This recovery plan action needs to be initiated from the other SRM instance" + } + + $RecoveryPlan.Start($RecoveryMode, $rpOpt) + } +} + +<# +.SYNOPSIS +Stop a running Recovery Plan action. + +.PARAMETER RecoveryPlan +The recovery plan to stop +#> +Function Stop-RecoveryPlan { + [cmdletbinding(SupportsShouldProcess=$True,ConfirmImpact="High")] + Param( + [Parameter (Mandatory=$true, ValueFromPipeline=$true, Position=1)][VMware.VimAutomation.Srm.Views.SrmRecoveryPlan] $RecoveryPlan + ) + + # Validate with informative error messages + $rpinfo = $RecoveryPlan.GetInfo() + + # Prompt the user to confirm they want to cancel the running action + if ($pscmdlet.ShouldProcess($rpinfo.Name, 'Cancel')) { + + $RecoveryPlan.Cancel() + } +} + +<# +.SYNOPSIS +Retrieve the historical results of a recovery plan + +.PARAMETER RecoveryPlan +The recovery plan to retrieve the history for +#> +Function Get-RecoveryPlanResult { + [cmdletbinding()] + Param( + [Parameter (Mandatory=$true, ValueFromPipeline=$true, Position=1)][VMware.VimAutomation.Srm.Views.SrmRecoveryPlan] $RecoveryPlan, + [VMware.VimAutomation.Srm.Views.SrmRecoveryPlanRecoveryMode] $RecoveryMode, + [VMware.VimAutomation.Srm.Views.SrmRecoveryResultResultState] $ResultState, + [DateTime] $StartedAfter, + [DateTime] $startedBefore, + [VMware.VimAutomation.Srm.Types.V1.SrmServer] $SrmServer + ) + + $api = Get-ServerApiEndpoint -SrmServer $SrmServer + + # Get the history objects + $history = $api.Recovery.GetHistory($RecoveryPlan.MoRef) + $resultCount = $history.GetResultCount() + + if ($resultCount -gt 0) { + $results = $history.GetRecoveryResult($resultCount) + + $results | + Where-Object { -not $RecoveryMode -or $_.RunMode -eq $RecoveryMode } | + Where-Object { -not $ResultState -or $_.ResultState -eq $ResultState } | + Where-Object { $null -eq $StartedAfter -or $_.StartTime -gt $StartedAfter } | + Where-Object { $null -eq $StartedBefore -or $_.StartTime -lt $StartedBefore } + } +} + +<# +.SYNOPSIS +Exports a recovery plan result object to XML format + +.PARAMETER RecoveryPlanResult +The recovery plan result to export +#> +Function Export-RecoveryPlanResultAsXml { + [cmdletbinding()] + [OutputType([xml])] + Param( + [Parameter (Mandatory=$true, ValueFromPipeline=$true, Position=1)][VMware.VimAutomation.Srm.Views.SrmRecoveryResult] $RecoveryPlanResult, + [VMware.VimAutomation.Srm.Types.V1.SrmServer] $SrmServer + ) + + $api = Get-ServerApiEndpoint -SrmServer $SrmServer + + $RecoveryPlan = $RecoveryPlanResult.Plan + $history = $api.Recovery.GetHistory($RecoveryPlan.MoRef) + $lines = $history.GetResultLength($RecoveryPlanResult.Key) + [xml] $history.RetrieveStatus($RecoveryPlanResult.Key, 0, $lines) +} + +<# +.SYNOPSIS +Add a protection group to a recovery plan. This requires SRM 5.8 or later. + +.PARAMETER RecoveryPlan +The recovery plan the protection group will be associated with + +.PARAMETER ProtectionGroup +The protection group to associate with the recovery plan +#> +Function Add-ProtectionGroupToRecoveryPlan { + [cmdletbinding()] + Param( + [Parameter (Mandatory=$true, Position=1)][VMware.VimAutomation.Srm.Views.SrmRecoveryPlan] $RecoveryPlan, + [Parameter (Mandatory=$true, ValueFromPipeline=$true, Position=2)][VMware.VimAutomation.Srm.Views.SrmProtectionGroup] $ProtectionGroup + ) + + if ($RecoveryPlan -and $ProtectionGroup) { + foreach ($pg in $ProtectionGroup) { + try { + $RecoveryPlan.AddProtectionGroup($pg.MoRef) + } catch { + Write-Error $_ + } + } + } +} + +<# +.SYNOPSIS +Remove a protection group to a recovery plan. This requires SRM 6.5 or later. + +.PARAMETER RecoveryPlan +The recovery plan the protection group will be disassociated from + +.PARAMETER ProtectionGroup +The protection group to disassociate from the recovery plan +#> +Function Remove-ProtectionGroupFromRecoveryPlan { + [cmdletbinding()] + Param( + [Parameter (Mandatory=$true)][VMware.VimAutomation.Srm.Views.SrmRecoveryPlan] $RecoveryPlan, + [Parameter (Mandatory=$true)][VMware.VimAutomation.Srm.Views.SrmProtectionGroup] $ProtectionGroup + ) + + if ($RecoveryPlan -and $ProtectionGroup) { + foreach ($pg in $ProtectionGroup) { + try { + $RecoveryPlan.RemoveProtectionGroupFromRecoveryPlan($pg.MoRef) + } catch { + Write-Error $_ + } + } + } +} + +<# +.SYNOPSIS +Get the recovery settings of a protected VM. This requires SRM 5.8 or later. + +.PARAMETER RecoveryPlan +The recovery plan the settings will be retrieved from. + +.PARAMETER Vm +The virtual machine to retieve recovery settings for. + +#> +Function Get-RecoverySetting { + [cmdletbinding()] + Param( + [Parameter (Mandatory=$true)][VMware.VimAutomation.Srm.Views.SrmRecoveryPlan] $RecoveryPlan, + [Parameter (ValueFromPipeline=$true)][VMware.VimAutomation.ViCore.Types.V1.Inventory.VirtualMachine] $Vm, + [Parameter (ValueFromPipeline=$true)][VMware.Vim.VirtualMachine] $VmView, + [Parameter (ValueFromPipeline=$true)][VMware.VimAutomation.Srm.Views.SrmProtectionGroupProtectedVm] $ProtectedVm + ) + + $moRef = Get_MoRefFromVmObj -Vm $Vm -VmView $VmView -ProtectedVm $ProtectedVm + + if ($RecoveryPlan -and $moRef) { + $RecoveryPlan.GetRecoverySettings($moRef) + } +} + +<# +.SYNOPSIS +Get the recovery settings of a protected VM. This requires SRM 5.8 or later. + +.PARAMETER RecoveryPlan +The recovery plan the settings will be retrieved from. + +.PARAMETER Vm +The virtual machine to configure recovery settings on. + +.PARAMETER RecoverySettings +The recovery settings to configure. These should have been retrieved via a +call to Get-RecoverySettings + +#> +Function Set-RecoverySetting { + [cmdletbinding(SupportsShouldProcess=$true, ConfirmImpact="Medium")] + Param( + [Parameter (Mandatory=$true)][VMware.VimAutomation.Srm.Views.SrmRecoveryPlan] $RecoveryPlan, + [Parameter (ValueFromPipeline=$true)][VMware.VimAutomation.ViCore.Types.V1.Inventory.VirtualMachine] $Vm, + [Parameter (ValueFromPipeline=$true)][VMware.Vim.VirtualMachine] $VmView, + [Parameter (ValueFromPipeline=$true)][VMware.VimAutomation.Srm.Views.SrmProtectionGroupProtectedVm] $ProtectedVm, + [Parameter (Mandatory=$true, ValueFromPipeline=$true)][VMware.VimAutomation.Srm.Views.SrmRecoverySettings] $RecoverySettings + ) + + + $moRef = Get_MoRefFromVmObj -Vm $Vm -VmView $VmView -ProtectedVm $ProtectedVm + + if ($RecoveryPlan -and $moRef -and $RecoverySettings) { + if ($PSCmdlet.ShouldProcess("$moRef", "Set")) { + $RecoveryPlan.SetRecoverySettings($moRef, $RecoverySettings) + } + } +} + +<# +.SYNOPSIS +Create a new per-Vm command to add to the SRM Recovery Plan + +.PARAMETER Command +The command script to execute. + +.PARAMETER Description +The user friendly description of this script. + +.PARAMETER Timeout +The number of seconds this command has to execute before it will be timedout. + +.PARAMETER RunInRecoveredVm +For a post-power on command this flag determines whether it will run on the +recovered VM or on the SRM server. + +#> +Function New-Command { + [cmdletbinding(SupportsShouldProcess=$true, ConfirmImpact="None")] + Param( + [Parameter (Mandatory=$true)][string] $Command, + [Parameter (Mandatory=$true)][string] $Description, + [int] $Timeout = 300, + [switch] $RunInRecoveredVm = $false + ) + + if($PSCmdlet.ShouldProcess("Description", "New")) { + $srmWsdlCmd = New-Object VMware.VimAutomation.Srm.WsdlTypes.SrmCommand + $srmCmd = New-Object VMware.VimAutomation.Srm.Views.SrmCommand -ArgumentList $srmWsdlCmd + $srmCmd.Command = $Command + $srmCmd.Description = $Description + $srmCmd.RunInRecoveredVm = $RunInRecoveredVm + $srmCmd.Timeout = $Timeout + $srmCmd.Uuid = [guid]::NewGuid() + + return $srmCmd + } +} + +<# Internal function #> +Function Add_Command { + [cmdletbinding()] + Param( + [Parameter (Mandatory=$true, ValueFromPipeline=$true)][VMware.VimAutomation.Srm.Views.SrmRecoverySettings] $RecoverySettings, + [Parameter (Mandatory=$true)][VMware.VimAutomation.Srm.Views.SrmCommand] $SrmCommand, + [Parameter (Mandatory=$true)][bool] $PostRecovery + ) + + if ($PostRecovery) { + $commands = $RecoverySettings.PostPowerOnCallouts + } else { + $commands = $RecoverySettings.PrePowerOnCallouts + } + + if (-not $commands) { + $commands = New-Object System.Collections.Generic.List[VMware.VimAutomation.Srm.Views.SrmCallout] + } + $commands.Add($SrmCommand) + + if ($PostRecovery) { + $RecoverySettings.PostPowerOnCallouts = $commands + } else { + $RecoverySettings.PrePowerOnCallouts = $commands + } +} + +<# +.SYNOPSIS +Add an SRM command to the set of pre recovery callouts for a VM. + +.PARAMETER RecoverySettings +The recovery settings to update. These should have been retrieved via a +call to Get-RecoverySettings + +.PARAMETER SrmCommand +The command to add to the list. + +#> +Function Add-PreRecoveryCommand { + [cmdletbinding()] + [OutputType([VMware.VimAutomation.Srm.Views.SrmRecoverySettings])] + Param( + [Parameter (Mandatory=$true, ValueFromPipeline=$true)][VMware.VimAutomation.Srm.Views.SrmRecoverySettings] $RecoverySettings, + [Parameter (Mandatory=$true)][VMware.VimAutomation.Srm.Views.SrmCommand] $SrmCommand + ) + Add_Command -RecoverySettings $RecoverySettings -SrmCommand $SrmCommand -PostRecovery $false + return $RecoverySettings +} + +<# +.SYNOPSIS +Remove an SRM command from the set of pre recovery callouts for a VM. + +.PARAMETER RecoverySettings +The recovery settings to update. These should have been retrieved via a +call to Get-RecoverySettings + +.PARAMETER SrmCommand +The command to remove from the list. + +#> +Function Remove-PreRecoveryCommand { + [cmdletbinding(SupportsShouldProcess=$true, ConfirmImpact="Low")] + [OutputType([VMware.VimAutomation.Srm.Views.SrmRecoverySettings])] + Param( + [Parameter (Mandatory=$true, ValueFromPipeline=$true)][VMware.VimAutomation.Srm.Views.SrmRecoverySettings] $RecoverySettings, + [Parameter (Mandatory=$true)][VMware.VimAutomation.Srm.Views.SrmCommand] $SrmCommand + ) + + if ($pscmdlet.ShouldProcess($SrmCommand.Description, "Remove")) { + $RecoverySettings.PrePowerOnCallouts.Remove($SrmCommand) + } + + return $RecoverySettings +} + +<# +.SYNOPSIS +Add an SRM command to the set of post recovery callouts for a VM. + +.PARAMETER RecoverySettings +The recovery settings to update. These should have been retrieved via a +call to Get-RecoverySettings + +.PARAMETER SrmCommand +The command to add to the list. + +#> +Function Add-PostRecoveryCommand { + [cmdletbinding()] + [OutputType([VMware.VimAutomation.Srm.Views.SrmRecoverySettings])] + Param( + [Parameter (Mandatory=$true, ValueFromPipeline=$true)][VMware.VimAutomation.Srm.Views.SrmRecoverySettings] $RecoverySettings, + [Parameter (Mandatory=$true)][VMware.VimAutomation.Srm.Views.SrmCommand] $SrmCommand + ) + + Add_Command -RecoverySettings $RecoverySettings -SrmCommand $SrmCommand -PostRecovery $true + + return $RecoverySettings +} + + +<# +.SYNOPSIS +Remove an SRM command from the set of post recovery callouts for a VM. + +.PARAMETER RecoverySettings +The recovery settings to update. These should have been retrieved via a +call to Get-RecoverySettings + +.PARAMETER SrmCommand +The command to remove from the list. + +#> +Function Remove-PostRecoveryCommand { + [cmdletbinding(SupportsShouldProcess=$true, ConfirmImpact="Low")] + [OutputType([VMware.VimAutomation.Srm.Views.SrmRecoverySettings])] + Param( + [Parameter (Mandatory=$true, ValueFromPipeline=$true)][VMware.VimAutomation.Srm.Views.SrmRecoverySettings] $RecoverySettings, + [Parameter (Mandatory=$true)][VMware.VimAutomation.Srm.Views.SrmCommand] $SrmCommand + ) + + if ($pscmdlet.ShouldProcess($SrmCommand.Description, "Remove")) { + $RecoverySettings.PostPowerOnCallouts.Remove($SrmCommand) + } + + return $RecoverySettings +} + + +<# +.SYNOPSIS +Create a new recovery plan + +.PARAMETER Name +The name for this recovery plan + +.PARAMETER Description +A description of the recovery plan + +.PARAMETER Folder +The recovery plan folder in which to create this recovery plan. Will default to +the root recovery plan folder + +.PARAMETER ProtectionGroups +The protection groups to associate with this recovery plan + +.PARAMETER TestNetworkMappings +The test network mappings to configure as part of this recovery plan + +.PARAMETER SrmServer +The SRM Server to operate against +#> +Function New-RecoveryPlan { + [cmdletbinding(SupportsShouldProcess=$true, ConfirmImpact="Medium")] + Param( + [Parameter (Mandatory=$true)][string] $Name, + [string] $Description, + [VMware.VimAutomation.Srm.Views.SrmRecoveryPlanFolder] $Folder, + [VMware.VimAutomation.Srm.Views.SrmProtectionGroup[]] $ProtectionGroups, + [VMware.VimAutomation.Srm.Views.SrmRecoveryTestNetworkMapping[]] $TestNetworkMappings, + [VMware.VimAutomation.Srm.Types.V1.SrmServer] $SrmServer + ) + + $api = Get-ServerApiEndpoint -SrmServer $SrmServer + + if (-not $Folder) { + $Folder = Get-RecoveryPlanFolder -SrmServer $SrmServer + } + + $protectionGroupmRefs += @( $ProtectionGroups | ForEach-Object { $_.MoRef } | Select-Object -Unique) + + [VMware.VimAutomation.Srm.Views.CreateRecoveryPlanTask] $task = $null + + if ($PSCmdlet.ShouldProcess($Name, "New")) { + $task = $api.Recovery.CreateRecoveryPlan( + $Name, + $Folder.MoRef, + $protectionGroupmRefs, + $Description, + $TestNetworkMappings + ) + } + + while(-not $task.IsCreateRecoveryPlanComplete()) { Start-Sleep -Seconds 1 } + + $task.GetNewRecoveryPlan() +} + +<# +.SYNOPSIS +Remove a recovery plan permanently + +.PARAMETER RecoveryPlan +The recovery plan to remove + +.PARAMETER SrmServer +The SRM Server to operate against +#> +Function Remove-RecoveryPlan { + [cmdletbinding(SupportsShouldProcess=$True, ConfirmImpact="High")] + Param( + [Parameter (Mandatory=$true)][VMware.VimAutomation.Srm.Views.SrmRecoveryPlan] $RecoveryPlan, + [VMware.VimAutomation.Srm.Types.V1.SrmServer] $SrmServer + ) + + $api = Get-ServerApiEndpoint -SrmServer $SrmServer + + $rpinfo = $RecoveryPlan.GetInfo() + if ($pscmdlet.ShouldProcess($rpinfo.Name, "Remove")) { + $api.Recovery.DeleteRecoveryPlan($RecoveryPlan.MoRef) + } +} + +<# +.SYNOPSIS +Get a recovery plan folder + +.PARAMETER SrmServer +The SRM Server to query for the recovery plan folder +#> +Function Get-RecoveryPlanFolder { + [cmdletbinding()] + Param( + [VMware.VimAutomation.Srm.Types.V1.SrmServer] $SrmServer + ) + + $api = Get-ServerApiEndpoint -SrmServer $SrmServer + + $folder = $api.Recovery.GetRecoveryPlanRootFolder() + + return $folder +} diff --git a/Modules/SRM/Meadowcroft.Srm.Storage.ps1 b/Modules/SRM/Meadowcroft.Srm.Storage.ps1 new file mode 100644 index 0000000..8880f36 --- /dev/null +++ b/Modules/SRM/Meadowcroft.Srm.Storage.ps1 @@ -0,0 +1,24 @@ +# SRM Helper Methods - https://github.com/benmeadowcroft/SRM-Cmdlets + +<# +.SYNOPSIS +Trigger Discover Devices for Site Recovery Manager + +.OUTPUTS +Returns discover devices task +#> +Function Start-DiscoverDevice { + [cmdletbinding(SupportsShouldProcess=$True, ConfirmImpact="Medium")] + [OutputType([VMware.VimAutomation.Srm.Views.DiscoverDevicesTask])] + Param( + [VMware.VimAutomation.Srm.Types.V1.SrmServer] $SrmServer + ) + + $api = Get-ServerApiEndpoint -SrmServer $SrmServer + $name = $SrmServer.Name + [VMware.VimAutomation.Srm.Views.DiscoverDevicesTask] $task = $null + if ($pscmdlet.ShouldProcess($name, "Rescan Storage Devices")) { + $task = $api.Storage.DiscoverDevices() + } + return $task +} diff --git a/Modules/SRM/Meadowcroft.Srm.psd1 b/Modules/SRM/Meadowcroft.Srm.psd1 new file mode 100644 index 0000000..996a493 --- /dev/null +++ b/Modules/SRM/Meadowcroft.Srm.psd1 @@ -0,0 +1,92 @@ +# +# Module manifest for module 'Meadowcroft.Srm' +# + +@{ + +# Script module or binary module file associated with this manifest. +RootModule = 'Meadowcroft.Srm.psm1' + +# Version number of this module. +ModuleVersion = '0.2' + +# ID used to uniquely identify this module +GUID = 'f9247009-9168-4a21-831b-819f82884ffe' + +# Author of this module +Author = 'Ben Meadowcroft' + +# Company or vendor of this module +CompanyName = 'VMware, Inc' + +# Copyright statement for this module +Copyright = '(c) 2014 - 2017. All rights reserved.' + +# Description of the functionality provided by this module +# Description = '' + +# Minimum version of the Windows PowerShell engine required by this module +# PowerShellVersion = '' + +# Name of the Windows PowerShell host required by this module +# PowerShellHostName = '' + +# Minimum version of the Windows PowerShell host required by this module +# PowerShellHostVersion = '' + +# Minimum version of Microsoft .NET Framework required by this module +# DotNetFrameworkVersion = '' + +# Minimum version of the common language runtime (CLR) required by this module +# CLRVersion = '' + +# Processor architecture (None, X86, Amd64) required by this module +# ProcessorArchitecture = '' + +# Modules that must be imported into the global environment prior to importing this module +RequiredModules = @{ModuleName='VMware.VimAutomation.Srm'; ModuleVersion='6.5'} + +# Assemblies that must be loaded prior to importing this module +# RequiredAssemblies = @() + +# Script files (.ps1) that are run in the caller's environment prior to importing this module. +# ScriptsToProcess = @() + +# Type files (.ps1xml) to be loaded when importing this module +# TypesToProcess = @() + +# Format files (.ps1xml) to be loaded when importing this module +# FormatsToProcess = @() + +# Modules to import as nested modules of the module specified in RootModule/ModuleToProcess +NestedModules = 'Meadowcroft.Srm.Recovery.ps1','Meadowcroft.Srm.Protection.ps1','Meadowcroft.Srm.Storage.ps1' +# NestedModules = @() + +# Functions to export from this module, note that internal functions use '_' not '-' as separator +FunctionsToExport = '*-*' + +# Cmdlets to export from this module +CmdletsToExport = '*' + +# Variables to export from this module +VariablesToExport = '*' + +# Aliases to export from this module +AliasesToExport = '*' + +# List of all modules packaged with this module +# ModuleList = @() + +# List of all files packaged with this module +# FileList = @() + +# Private data to pass to the module specified in RootModule/ModuleToProcess +# PrivateData = '' + +# HelpInfo URI of this module +# HelpInfoURI = '' + +# Default prefix for commands exported from this module. Override the default prefix using Import-Module -Prefix. +DefaultCommandPrefix = 'Srm' + +} diff --git a/Modules/SRM/Meadowcroft.Srm.psm1 b/Modules/SRM/Meadowcroft.Srm.psm1 new file mode 100644 index 0000000..ed7c042 --- /dev/null +++ b/Modules/SRM/Meadowcroft.Srm.psm1 @@ -0,0 +1,148 @@ +# SRM Helper Methods - https://github.com/benmeadowcroft/SRM-Cmdlets + +<# +.SYNOPSIS +This is intended to be an "internal" function only. It filters a +pipelined input of objects and elimiates duplicates as identified +by the MoRef property on the object. + +.LINK +https://github.com/benmeadowcroft/SRM-Cmdlets/ +#> +Function Select_UniqueByMoRef { + + Param( + [Parameter (ValueFromPipeline=$true)] $in + ) + process { + $moref = New-Object System.Collections.ArrayList + $in | Sort-Object | Select-Object MoRef -Unique | ForEach-Object { $moref.Add($_.MoRef) } > $null + $in | ForEach-Object { + if ($_.MoRef -in $moref) { + $moref.Remove($_.MoRef) + $_ #output + } + } + } +} + +<# +.SYNOPSIS +This is intended to be an "internal" function only. It gets the +MoRef property of a VM from either a VM object, a VM view, or the +protected VM object. +#> +Function Get_MoRefFromVmObj { + Param( + [Parameter (ValueFromPipeline=$true)][VMware.VimAutomation.ViCore.Types.V1.Inventory.VirtualMachine] $Vm, + [Parameter (ValueFromPipeline=$true)][VMware.Vim.VirtualMachine] $VmView, + [Parameter (ValueFromPipeline=$true)][VMware.VimAutomation.Srm.Views.SrmProtectionGroupProtectedVm] $ProtectedVm + ) + + + $moRef = $null + if ($Vm.ExtensionData.MoRef) { # VM object + $moRef = $Vm.ExtensionData.MoRef + } elseif ($VmView.MoRef) { # VM view + $moRef = $VmView.MoRef + } elseif ($protectedVm) { + $moRef = $ProtectedVm.Vm.MoRef + } + + $moRef +} + +<# +.SYNOPSIS +Lookup the srm instance for a specific server. +#> +Function Get-Server { + [cmdletbinding()] + Param( + [string] $SrmServerAddress, + [VMware.VimAutomation.Srm.Types.V1.SrmServer] $SrmServer + ) + + $found = $null + + if ($SrmServer) { + $found = $SrmServer + } elseif ($SrmServerAddress) { + # search for server address in default servers + $global:DefaultSrmServers | ForEach-Object { + if ($_.Name -ieq $SrmServerAddress) { + $found = $_ + } + } + if (-not $found) { + throw "SRM server $SrmServerAddress not found. Connect-Server must be called first." + } + } + + if (-not $found) { + #default result + $found = $global:DefaultSrmServers[0] + } + + return $found; +} + +<# +.SYNOPSIS +Retrieve the SRM Server Version +#> +Function Get-ServerVersion { + [cmdletbinding()] + Param( + [VMware.VimAutomation.Srm.Types.V1.SrmServer] $SrmServer + ) + $srm = Get-Server $SrmServer + $srm.Version +} + +<# +.SYNOPSIS +Lookup the SRM API endpoint for a specific server. +#> +Function Get-ServerApiEndpoint { + [cmdletbinding()] + Param( + [string] $SrmServerAddress, + [VMware.VimAutomation.Srm.Types.V1.SrmServer] $SrmServer + ) + + [VMware.VimAutomation.Srm.Types.V1.SrmServer] $server = Get-Server -SrmServerAddress $SrmServerAddress -SrmServer $SrmServer + + return $server.ExtensionData +} + +<# +.SYNOPSIS +Get the placeholder VMs that are associated with SRM +#> +Function Get-PlaceholderVM { + [cmdletbinding()] + Param() + Get-VM @Args | Where-Object {$_.ExtensionData.Config.ManagedBy.extensionKey -like "com.vmware.vcDr*" -and $_.ExtensionData.Config.ManagedBy.Type -ieq 'placeholderVm'} +} + +<# +.SYNOPSIS +Get the test VMs that are associated with SRM +#> +Function Get-TestVM { + [cmdletbinding()] + Param() + Get-VM @Args | Where-Object {$_.ExtensionData.Config.ManagedBy.extensionKey -like "com.vmware.vcDr*" -and $_.ExtensionData.Config.ManagedBy.Type -ieq 'testVm'} +} + +<# +.SYNOPSIS +Get the VMs that are replicated using vSphere Replication. These may not be SRM +protected VMs. +#> +Function Get-ReplicatedVM { + [cmdletbinding()] + Param() + Get-VM @Args | Where-Object {($_.ExtensionData.Config.ExtraConfig | Where-Object { $_.Key -eq 'hbr_filter.destination' -and $_.Value } )} +} diff --git a/Modules/SRM/NOTICE.txt b/Modules/SRM/NOTICE.txt new file mode 100644 index 0000000..2eb2d48 --- /dev/null +++ b/Modules/SRM/NOTICE.txt @@ -0,0 +1,7 @@ + +Copyright (c) 2017 VMware, Inc. All Rights Reserved. + +This product is licensed to you under the Apache License version 2.0 (the "License"). You may not use this product except in compliance with the License. + +This product may include a number of subcomponents with separate copyright notices and license terms. Your use of these subcomponents is subject to the terms and conditions of the subcomponent's license, as noted in the LICENSE file. + diff --git a/Modules/SRM/README.md b/Modules/SRM/README.md new file mode 100644 index 0000000..00d775e --- /dev/null +++ b/Modules/SRM/README.md @@ -0,0 +1,81 @@ +# SRM PowerCLI Cmdlets + +Helper functions for working with VMware SRM 6.5 with PowerCLI 6.5.1 or later. PowerShell 5.0 and above is required. + +This module is provided for illustrative/educational purposes to explain how the PowerCLI access to the SRM public API can be used. + +## Getting Started + +### Getting the SRM cmdlets + +The latest version of the software can be cloned from the git repository: + + git clone https://github.com/benmeadowcroft/SRM-Cmdlets.git + +Or downloaded as a [zip file](https://github.com/benmeadowcroft/SRM-Cmdlets/archive/master.zip). + +Specific releases (compatible with earlier PowerCLI and SRM versions) can be downloaded via the [release page](https://github.com/benmeadowcroft/SRM-Cmdlets/releases). + +### Deploy SRM-Cmdlets module + +After cloning (or downloading and extracting) the PowerShell module, you can import the module into your current PowerShell session by by passing the path to `Meadowcroft.Srm.psd1` to the `Import-Module` cmdlet, e.g.: + + Import-Module -Name .\SRM-Cmdlets\Meadowcroft.Srm.psd1 + +You can also install the module into the PowerShell path so it can be loaded implicitly. See [Microsoft's Installing Modules instructions](http://msdn.microsoft.com/en-us/library/dd878350) for more details on how to do this. + +The module uses the default prefix of `Srm` for the custom functions it defines. This can be overridden when importing the module by setting the value of the `-Prefix` parameter when calling `Import-Module`. + +### Connecting to SRM + +After installing the module the next step is to connect to the SRM server. Details of how to do this are located in the [PowerCLI 6.5.1 User's Guide](http://pubs.vmware.com/vsphere-65/topic/com.vmware.powercli.ug.doc/GUID-A5F206CF-264D-4565-8CB9-4ED1C337053F.html) + + $credential = Get-Credential + Connect-VIServer -Server vc-a.example.com -Credential $credential + Connect-SrmServer -Credential $credential -RemoteCredential $credential + +At this point we've just been using the cmdlets provided by PowerCLI, the PowerCLI documentation also provides some examples of how to call the SRM API to perform various tasks. In the rest of this introduction we'll perform some of those tasks using the custom functions defined in this project. + +### Report the Protected Virtual Machines and Their Protection Groups + +Goal: Create a simple report listing the VMs protected by SRM and the protection group they belong to. + + Get-SrmProtectionGroup | %{ + $pg = $_ + Get-SrmProtectedVM -ProtectionGroup $pg } | %{ + $output = "" | select VmName, PgName + $output.VmName = $_.Vm.Name + $output.PgName = $pg.GetInfo().Name + $output + } | Format-Table @{Label="VM Name"; Expression={$_.VmName} }, + @{Label="Protection group name"; Expression={$_.PgName} + } + +### Report the Last Recovery Plan Test + +Goal: Create a simple report listing the state of the last test of a recovery plan + + Get-SrmRecoveryPlan | %{ $_ | + Get-SrmRecoveryPlanResult -RecoveryMode Test | select -First 1 + } | Select Name, StartTime, RunMode, ResultState | Format-Table + + +### Execute a Recovery Plan Test + +Goal: for a specific recovery plan, execute a test failover. Note the "local" SRM server we are connected to should be the recovery site in order for this to be successful. + + Get-SrmRecoveryPlan -Name "Name of Plan" | Start-SrmRecoveryPlan -RecoveryMode Test + +### Export the Detailed XML Report of the Last Recovery Plan Workflow + +Goal: get the XML report of the last recovery plan execution for a specific recovery plan. + + Get-SrmRecoveryPlan -Name "Name of Plan" | Get-SrmRecoveryPlanResult | + select -First 1 | Export-SrmRecoveryPlanResultAsXml + +### Protect a Replicated VM + +Goal: Take a VM replicated using vSphere Replication or Array Based Replication, add it to an appropriate protection group and configure it for protection + + $pg = Get-SrmProtectionGroup "Name of Protection Group" + Get-VM vm-01a | Protect-SrmVM -ProtectionGroup $pg From e0e4a568267859d0a845eb46ed413ea755746a00 Mon Sep 17 00:00:00 2001 From: alanrenouf Date: Wed, 31 Jan 2018 20:40:39 -0800 Subject: [PATCH 27/29] updated module with VMC Firewall functions --- Modules/VMware.VMC/VMware.VMC.psd1 | Bin 7976 -> 8176 bytes Modules/VMware.VMC/VMware.VMC.psm1 | 371 ++++++++++++++++++++++++++++- 2 files changed, 370 insertions(+), 1 deletion(-) diff --git a/Modules/VMware.VMC/VMware.VMC.psd1 b/Modules/VMware.VMC/VMware.VMC.psd1 index 74256ef01bb8a2e4a146aa91e45b35b01949b08f..d2f3b23eb599158b576193db188ce27bfb1746d0 100755 GIT binary patch delta 206 zcmZ2s_rZRH6ceN2W@#pA!O2QOBK2+znG8h?sSM=|i3~YF7{pKtBvTpG8FUyFfTSx! w1w#QtK2S{wgDyiDgD-V6ceMtW@#pAK}N34|Ajwt0{~8O2HOAt diff --git a/Modules/VMware.VMC/VMware.VMC.psm1 b/Modules/VMware.VMC/VMware.VMC.psm1 index 674668b..3af0ad0 100644 --- a/Modules/VMware.VMC/VMware.VMC.psm1 +++ b/Modules/VMware.VMC/VMware.VMC.psm1 @@ -320,4 +320,373 @@ Function Get-VMCSDDCVersion { } } } -Export-ModuleMember -Function 'Get-VMCCommand', 'Connect-VMCVIServer', 'Get-VMCOrg', 'Get-VMCSDDC', 'Get-VMCTask', 'Get-VMCSDDCDefaultCredential', 'Get-VMCSDDCPublicIP', 'Get-VMCVMHost', 'Get-VMCSDDCVersion' \ No newline at end of file + +Function Get-VMCFirewallRule { + <# + .NOTES + =========================================================================== + Created by: William Lam + Date: 11/19/2017 + Organization: VMware + Blog: https://www.virtuallyghetto.com + Twitter: @lamw + =========================================================================== + + .SYNOPSIS + Retruns VMC Firewall Rules for a given Gateway (MGW or CGW) + .DESCRIPTION + Retruns VMC Firewall Rules for a given Gateway (MGW or CGW) + .EXAMPLE + Get-VMCFirewallRule -OrgName -SDDCName -GatewayType + .EXAMPLE + Get-VMCFirewallRule -OrgName -SDDCName -GatewayType -ShowAll + #> + param( + [Parameter(Mandatory=$false)][String]$SDDCName, + [Parameter(Mandatory=$false)][String]$OrgName, + [Parameter(Mandatory=$false)][Switch]$ShowAll, + [Parameter(Mandatory=$true)][ValidateSet("MGW","CGW")][String]$GatewayType + ) + + if($GatewayType -eq "MGW") { + $EdgeId = "edge-1" + } else { + $EdgeId = "edge-2" + } + + $orgId = (Get-VMCOrg -Name $OrgName).Id + $sddcId = (Get-VMCSDDC -Name $SDDCName -Org $OrgName).Id + + $firewallConfigService = Get-VmcService com.vmware.vmc.orgs.sddcs.networks.edges.firewall.config + + $firewallRules = ($firewallConfigService.get($orgId, $sddcId, $EdgeId)).firewall_rules.firewall_rules + if(-not $ShowAll) { + $firewallRules = $firewallRules | where { $_.rule_type -ne "default_policy" -and $_.rule_type -ne "internal_high" -and $_.name -ne "vSphere Cluster HA" -and $_.name -ne "Outbound Access" } | Sort-Object -Property rule_tag + } else { + $firewallRules = $firewallRules | Sort-Object -Property rule_tag + } + + $results = @() + foreach ($firewallRule in $firewallRules) { + if($firewallRule.source.ip_address.Count -ne 0) { + $source = $firewallRule.source.ip_address + } else { $source = "ANY" } + + if($firewallRule.application.service.protocol -ne $null) { + $protocol = $firewallRule.application.service.protocol + } else { $protocol = "ANY" } + + if($firewallRule.application.service.port -ne $null) { + $port = $firewallRule.application.service.port + } else { $port = "ANY" } + + $tmp = [pscustomobject] @{ + ID = $firewallRule.rule_id; + Name = $firewallRule.name; + Type = $firewallRule.rule_type; + Action = $firewallRule.action; + Protocol = $protocol; + Port = $port; + SourceAddress = $source + DestinationAddress = $firewallRule.destination.ip_address; + } + $results+=$tmp + } + $results + } + + Function Export-VMCFirewallRule { + <# + .NOTES + =========================================================================== + Created by: William Lam + Date: 11/19/2017 + Organization: VMware + Blog: https://www.virtuallyghetto.com + Twitter: @lamw + =========================================================================== + + .SYNOPSIS + Exports all "customer" created VMC Firewall Rules to JSON file + .DESCRIPTION + Exports all "customer" created VMC Firewall Rules to JSON file + .EXAMPLE + Export-VMCFirewallRule -OrgName -SDDCName -GatewayType -Path "C:\Users\lamw\Desktop\VMCFirewallRules.json" + #> + param( + [Parameter(Mandatory=$false)][String]$SDDCName, + [Parameter(Mandatory=$false)][String]$OrgName, + [Parameter(Mandatory=$true)][ValidateSet("MGW","CGW")][String]$GatewayType, + [Parameter(Mandatory=$false)][String]$Path + ) + + if (-not $global:DefaultVMCServers) { Write-error "No VMC Connection found, please use the Connect-VMC to connect"; break } + + if($GatewayType -eq "MGW") { + $EdgeId = "edge-1" + } else { + $EdgeId = "edge-2" + } + + $orgId = (Get-VMCOrg -Name $OrgName).Id + $sddcId = (Get-VMCSDDC -Name $SDDCName -Org $OrgName).Id + + if(-not $orgId) { + Write-Host -ForegroundColor red "Unable to find Org $OrgName, please verify input" + break + } + if(-not $sddcId) { + Write-Host -ForegroundColor red "Unable to find SDDC $SDDCName, please verify input" + break + } + + $firewallConfigService = Get-VmcService com.vmware.vmc.orgs.sddcs.networks.edges.firewall.config + + $firewallRules = ($firewallConfigService.get($orgId, $sddcId, $EdgeId)).firewall_rules.firewall_rules + if(-not $ShowAll) { + $firewallRules = $firewallRules | where { $_.rule_type -ne "default_policy" -and $_.rule_type -ne "internal_high" -and $_.name -ne "vSphere Cluster HA" -and $_.name -ne "Outbound Access" } | Sort-Object -Property rule_tag + } else { + $firewallRules = $firewallRules | Sort-Object -Property rule_tag + } + + $results = @() + $count = 0 + foreach ($firewallRule in $firewallRules) { + if($firewallRule.source.ip_address.Count -ne 0) { + $source = $firewallRule.source.ip_address + } else { + $source = "ANY" + } + + $tmp = [pscustomobject] @{ + Name = $firewallRule.name; + Action = $firewallRule.action; + Protocol = $firewallRule.application.service.protocol; + Port = $firewallRule.application.service.port; + SourcePort = $firewallRule.application.service.source_port; + ICMPType = $firewallRule.application.service.icmp_type; + SourceAddress = $firewallRule.source.ip_address; + DestinationAddress = $firewallRule.destination.ip_address; + Enabled = $firewallRule.enabled; + Logging = $firewallRule.logging_enabled; + } + $count+=1 + $results+=$tmp + } + if($Path) { + Write-Host -ForegroundColor Green "Exporting $count VMC Firewall Rules to $Path ..." + $results | ConvertTo-Json | Out-File $Path + } else { + $results | ConvertTo-Json + } + } + + Function Import-VMCFirewallRule { + <# + .NOTES + =========================================================================== + Created by: William Lam + Date: 11/19/2017 + Organization: VMware + Blog: https://www.virtuallyghetto.com + Twitter: @lamw + =========================================================================== + + .SYNOPSIS + Imports VMC Firewall Rules from exported JSON configuration file + .DESCRIPTION + Imports VMC Firewall Rules from exported JSON configuration file + .EXAMPLE + Import-VMCFirewallRule -OrgName -SDDCName -GatewayType -Path "C:\Users\lamw\Desktop\VMCFirewallRules.json" + #> + param( + [Parameter(Mandatory=$false)][String]$SDDCName, + [Parameter(Mandatory=$false)][String]$OrgName, + [Parameter(Mandatory=$true)][ValidateSet("MGW","CGW")][String]$GatewayType, + [Parameter(Mandatory=$false)][String]$Path + ) + + if (-not $global:DefaultVMCServers) { Write-error "No VMC Connection found, please use the Connect-VMC to connect"; break } + + if($GatewayType -eq "MGW") { + $EdgeId = "edge-1" + } else { + $EdgeId = "edge-2" + } + + $orgId = (Get-VMCOrg -Name $OrgName).Id + $sddcId = (Get-VMCSDDC -Name $SDDCName -Org $OrgName).Id + + if(-not $orgId) { + Write-Host -ForegroundColor red "Unable to find Org $OrgName, please verify input" + break + } + if(-not $sddcId) { + Write-Host -ForegroundColor red "Unable to find SDDC $SDDCName, please verify input" + break + } + + $firewallService = Get-VmcService com.vmware.vmc.orgs.sddcs.networks.edges.firewall.config.rules + + $vmcFirewallRulesJSON = Get-Content -Raw $Path | ConvertFrom-Json + + # Create top level Firewall Rules Object + $firewallRules = $firewallService.Help.add.firewall_rules.Create() + # Create top top level Firewall Rule Spec which will be an array of individual Firewall rules as we process them in next section + $ruleSpec = $firewallService.Help.add.firewall_rules.firewall_rules.Create() + + foreach ($vmcFirewallRule in $vmcFirewallRulesJSON) { + # Create Individual Firewall Rule Element Spec + $ruleElementSpec = $firewallService.Help.add.firewall_rules.firewall_rules.Element.Create() + + # AppSpec + $appSpec = $firewallService.Help.add.firewall_rules.firewall_rules.Element.application.Create() + # ServiceSpec + $serviceSpec = $firewallService.Help.add.firewall_rules.firewall_rules.Element.application.service.Element.Create() + + $protocol = $null + if($vmcFirewallRule.Protocol -ne $null) { + $protocol = $vmcFirewallRule.Protocol + } + $serviceSpec.protocol = $protocol + + # Process ICMP Type from JSON + $icmpType = $null + if($vmcFirewallRule.ICMPType -ne $null) { + $icmpType = $vmcFirewallRule.ICMPType + } + $serviceSpec.icmp_type = $icmpType + + # Process Source Ports from JSON + $sourcePorts = @() + if($vmcFirewallRule.SourcePort -eq "any" -or $vmcFirewallRule.SourcePort -ne $null) { + foreach ($port in $vmcFirewallRule.SourcePort) { + $sourcePorts+=$port + } + } else { + $sourcePorts = @("any") + } + $serviceSpec.source_port = $sourcePorts + + # Process Ports from JSON + $ports = @() + if($vmcFirewallRule.Port -ne "null") { + foreach ($port in $vmcFirewallRule.Port) { + $ports+=$port + } + } + $serviceSpec.port = $ports + $addSpec = $appSpec.service.Add($serviceSpec) + + # Create Source Spec + $srcSpec = $firewallService.Help.add.firewall_rules.firewall_rules.Element.source.Create() + $srcSpec.exclude = $false + # Process Source Address from JSON + $sourceAddess = @() + if($vmcFirewallRule.SourceAddress -ne "null") { + foreach ($address in $vmcFirewallRule.SourceAddress) { + $sourceAddess+=$address + } + } + $srcSpec.ip_address = $sourceAddess; + + # Create Destination Spec + $destSpec = $firewallService.Help.add.firewall_rules.firewall_rules.Element.destination.Create() + $destSpec.exclude = $false + # Process Destination Address from JSON + $destinationAddess = @() + if($vmcFirewallRule.DestinationAddress -ne "null") { + foreach ($address in $vmcFirewallRule.DestinationAddress) { + $destinationAddess+=$address + } + } + $destSpec.ip_address = $destinationAddess + + # Add various specs + if($vmcFirewallRule.Protocol -ne $null -and $vmcFirewallRule.port -ne $null) { + $ruleElementSpec.application = $appSpec + } + + $ruleElementSpec.source = $srcSpec + $ruleElementSpec.destination = $destSpec + $ruleElementSpec.rule_type = "user" + + # Process Enabled from JSON + $fwEnabled = $false + if($vmcFirewallRule.Enabled -eq "true") { + $fwEnabled = $true + } + $ruleElementSpec.enabled = $fwEnabled + + # Process Logging from JSON + $loggingEnabled = $false + if($vmcFirewallRule.Logging -eq "true") { + $loggingEnabled = $true + } + $ruleElementSpec.logging_enabled = $loggingEnabled + + $ruleElementSpec.action = $vmcFirewallRule.Action + $ruleElementSpec.name = $vmcFirewallRule.Name + + # Add the individual FW rule spec into our overall firewall rules array + Write-host "Creating VMC Firewall Rule Spec:" $vmcFirewallRule.Name "..." + $ruleSpecAdd = $ruleSpec.Add($ruleElementSpec) + } + $firewallRules.firewall_rules = $ruleSpec + + Write-host "Adding VMC Firewall Rules ..." + $firewallRuleAdd = $firewallService.add($orgId,$sddcId,$EdgeId,$firewallRules) + } + + Function Remove-VMCFirewallRule { + <# + .NOTES + =========================================================================== + Created by: William Lam + Date: 11/19/2017 + Organization: VMware + Blog: https://www.virtuallyghetto.com + Twitter: @lamw + =========================================================================== + + .SYNOPSIS + Removes VMC Firewall Rule given Rule Id + .DESCRIPTION + Removes VMC Firewall Rule given Rule Id + .EXAMPLE + Import-VMCFirewallRule -OrgName -SDDCName -GatewayType -RuleId + #> + param( + [Parameter(Mandatory=$false)][String]$SDDCName, + [Parameter(Mandatory=$false)][String]$OrgName, + [Parameter(Mandatory=$true)][ValidateSet("MGW","CGW")][String]$GatewayType, + [Parameter(Mandatory=$false)][String]$RuleId + ) + + if (-not $global:DefaultVMCServers) { Write-error "No VMC Connection found, please use the Connect-VMC to connect"; break } + + if($GatewayType -eq "MGW") { + $EdgeId = "edge-1" + } else { + $EdgeId = "edge-2" + } + + $orgId = (Get-VMCOrg -Name $OrgName).Id + $sddcId = (Get-VMCSDDC -Name $SDDCName -Org $OrgName).Id + + if(-not $orgId) { + Write-Host -ForegroundColor red "Unable to find Org $OrgName, please verify input" + break + } + if(-not $sddcId) { + Write-Host -ForegroundColor red "Unable to find SDDC $SDDCName, please verify input" + break + } + + $firewallService = Get-VmcService com.vmware.vmc.orgs.sddcs.networks.edges.firewall.config.rules + Write-Host "Removing VMC Firewall Rule Id $RuleId ..." + $firewallService.delete($orgId,$sddcId,$EdgeId,$RuleId) + } + + +Export-ModuleMember -Function 'Get-VMCCommand', 'Connect-VMCVIServer', 'Get-VMCOrg', 'Get-VMCSDDC', 'Get-VMCTask', 'Get-VMCSDDCDefaultCredential', 'Get-VMCSDDCPublicIP', 'Get-VMCVMHost', 'Get-VMCSDDCVersion', 'Get-VMCFirewallRule', 'Export-VMCFirewallRule', 'Import-VMCFirewallRule', 'Remove-VMCFirewallRule' \ No newline at end of file From a9c83ab50a7288875120457d8990f50b9ca83cf2 Mon Sep 17 00:00:00 2001 From: alanrenouf Date: Wed, 31 Jan 2018 21:40:34 -0800 Subject: [PATCH 28/29] Added a VMC Firewall Rules example script --- .../Sample VMC firewall rules management.ps1 | 20 +++++++++++++++++++ 1 file changed, 20 insertions(+) create mode 100644 Scripts/Sample VMC firewall rules management.ps1 diff --git a/Scripts/Sample VMC firewall rules management.ps1 b/Scripts/Sample VMC firewall rules management.ps1 new file mode 100644 index 0000000..b62360b --- /dev/null +++ b/Scripts/Sample VMC firewall rules management.ps1 @@ -0,0 +1,20 @@ +$MyRefreshToken = "XXXX-XXXX-XXXX-XXXX" +Connect-VMC -RefreshToken $MyRefreshToken + +#List the user firewall Rules for MGW +Get-VMCFirewallRule -SDDCName "vGhetto" -OrgName "BashFest - Red Team" -GatewayType MGW + +#List the firewall rules including system firewall rules for MGW +Get-VMCFirewallRule -SDDCName "vGhetto" -OrgName "BashFest - Red Team" -GatewayType MGW -ShowAll + +#Export Firewall Rules from original SDDC +Export-VMCFirewallRule -SDDCName "vGhetto" -OrgName "BashFest - Red Team" -GatewayType MGW -Path ~/Desktop/VMCFirewallRules.json + +#Import Firewall Rules to new SDDC +Import-VMCFirewallRule -SDDCName “Single-Host-SDDC” -OrgName "BashFest - Red Team" -GatewayType MGW -Path ~/Desktop/VMCFirewallRules.json + +#Remove the firewall Rules we just created for the SDDC +$Rules = Get-VMCFirewallRule -SDDCName "Single-Host-SDDC" -OrgName "BashFest - Red Team" -GatewayType MGW +Foreach ($rule in $rules){ + Remove-VMCFirewallRule -SDDCName “Single-Host-SDDC” -OrgName "BashFest - Red Team" -GatewayType MGW -RuleId $rule.id +} \ No newline at end of file From 8a4abe7dd4c71d8997591455d87f300ff04a736e Mon Sep 17 00:00:00 2001 From: alanrenouf Date: Wed, 31 Jan 2018 22:18:58 -0800 Subject: [PATCH 29/29] Added a VMC example script --- Scripts/VMC Example Script.ps1 | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) create mode 100755 Scripts/VMC Example Script.ps1 diff --git a/Scripts/VMC Example Script.ps1 b/Scripts/VMC Example Script.ps1 new file mode 100755 index 0000000..d1f1fae --- /dev/null +++ b/Scripts/VMC Example Script.ps1 @@ -0,0 +1,34 @@ +#List the commands available for the VMC module +Get-VMCCommand + +#Connect to VMC +$MyRefreshToken = "XXXX-XXXX-XXXX-XXXX" +Connect-VMC -RefreshToken $MyRefreshToken + +#List the Orgs available to us +Get-VMCOrg + +#List the SDDCs +Get-VMCSDDC -Org BashFest* + +#List the Tasks for a particular Org +Get-VMCTask -Org BashFest* | Select-Object task_type, Sub_Status, start_time, End_time, user_name | Sort-Object Start_Time | Format-Table + +#Get the Public IPs for a SDDC +Get-VMCSDDCPublicIPPool -org bashfest* + +#Get all ESXi hosts for given SDDC +Get-VMCVMHost -org bashfest* -Sddc virtu-al + +#Get the credentials of a SDDC so we can login via vSphere cmdlets +Get-VMCSDDCDefaultCredential -org bashfest* -Sddc virtu-al + +#Connect to your VMC vCenter with default creds +Connect-VmcVIServer -org bashfest* -Sddc virtu-al + +#Run some vSphere cmdlets + +#List all VMs from On-Premises and VMC SDDC +Get-VM | Select vCenterServer, Name, PowerState, VMHost + +