AGMPowerCLINewFunctions.ps1
# Copyright 2022 Google Inc. All Rights Reserved. # # 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. Function New-AGMAppDiscovery ([string]$hostid,[string]$ipaddress,[string]$applianceid) { <# .SYNOPSIS Runs discovery against a host .EXAMPLE New-AGMAppDiscovery -hostid 5678 -applianceid 1415071155 Runs application discovery against the host with ID 5678 for appliance with ID 1415071155 .DESCRIPTION A function to run application discovery #> if ((!($hostid)) -and (!($ipaddress))) { [string]$hostid = Read-Host "Host to perform discovery on (press enter to use IP)" if (!($hostid)) { [string]$ipaddress = Read-Host "Host IP to perform discovery on" } } if (!($applianceid)) { [string]$applianceid = Read-Host "Appliance to perform discovery on" } if ($hostid) { $body = [ordered]@{ host = [ordered]@{ id=$hostid sources= @( @{ clusterid=$applianceid } ) } } } if ($ipaddress) { $body = [ordered]@{ cluster=$applianceid; type="standard"; ipaddress=$ipaddress } } $jsonbody = $body | ConvertTo-Json -depth 4 Post-AGMAPIData -endpoint /host/discover -body $jsonbody } Function New-AGMAppliance ([string]$ipaddress,[string]$username,[string]$password,[SecureString]$passwordenc,[switch]$dryrun) { <# .SYNOPSIS Adds a new appliance to AGM .EXAMPLE New-AGMAppliance ipaddress 10.194.0.38 -username admin -password password -dryrun | select-object approvaltoken,cluster,report This performs a dryrun to test if Appliance add will work. Pay close attention to the errcode in the report field and that the cluster field contains a clusterid. You also need to see an approval token. If everything looks good, run the command again without specifying -dryrun If you are feeling lucky you can choose to skip running the command without -dryrun .EXAMPLE New-AGMAppliance ipaddress 10.194.0.38 -username admin -password password This adds the Appliance and includes a dryrun. After it runs, then run Get-AGMAppliance to confirm the appliance has been added. .DESCRIPTION A function to add Appliances For password handling there are two parameters you can use: -password This is the Appliance password in plain text -passwordenc This is the Appliance password as a secure string. This can be used with Powershell 7 If you don't use either parameter you will be prompted to enter the password in a secure fashion. This can be used with Powershell 7 #> if (!($ipaddress)) { [string]$ipaddress = Read-Host "Appliance IP Address" } if (!($username)) { [string]$username = Read-Host "Appliance username" } if ((!($password)) -and (!($passwordenc))) { # prompt for a password [SecureString]$passwordenc = Read-Host "Password" -AsSecureString [string]$password = (Convertfrom-SecureString $passwordenc -AsPlainText) } if ($passwordenc) { [string]$password = (Convertfrom-SecureString $passwordenc -AsPlainText) } $body = [ordered]@{ ipaddress=$ipaddress; username=$username; password=$password } $jsonbody = $body | ConvertTo-Json $dryrungrab = Post-AGMAPIData -endpoint /cluster/dryrun -body $jsonbody if ($dryrun) { $dryrungrab return } if ($dryrungrab.approvaltoken) { $body = [ordered]@{ ipaddress=$ipaddress; username=$username; password=$password; approvaltoken=$dryrungrab.approvaltoken } $jsonbody = $body | ConvertTo-Json Post-AGMAPIData -endpoint /cluster -body $jsonbody } else { $dryrun } } Function New-AGMCloudVM ([string]$zone,[string]$id,[string]$credentialid,[string]$clusterid,[string]$applianceid,[string]$projectid,[string]$instanceid) { <# .SYNOPSIS Adds new Cloud VMs .EXAMPLE New-AGMCloudVM -credentialid 1234 -zone australia-southeast1-c -clusterid 144292692833 -instanceid 4240202854121875692 Adds VM with ID 4240202854121875692 to specified appliance .DESCRIPTION A function to add Cloud VMs Multiple vmids should be comma separated #> if (($applianceid) -and ($clusterid)) { Get-AGMErrorMessage -messagetoprint "Do not specify both applianceid and clusterid. Only clusterid is neeeed." return } if ($id) { $credentialid = $id } if (!($credentialid)) { [string]$credentialid = Read-Host "Credential ID" } if ($applianceid) { [string]$clusterid = $applianceid} if (!($clusterid)) { $clusterid = Read-Host "Cluster ID" } if (!($projectid)) { [string]$projectid = Read-Host "Project ID" } #if user doesn't specify name and zone, then learn them $credentialgrab = Get-AGMCredential -credentialid $credentialid if (!($credentialgrab.id)) { if ($credentialgrab.errormessage) { $credentialgrab } else { Get-AGMErrorMessage -messagetoprint "The credential ID $credentialid could not be found using Get-AGMCredential" } return } else { if (!($zone)) { $zone = $credentialgrab.region } } if (!($zone)) { [string]$zone = Read-Host "Zone Name" } if (!($instanceid)) { [string]$instanceid = Read-Host "Instance IDs (Comma separated)" } $cluster = @{ clusterid = $clusterid} $body = [ordered]@{} if ($AGMToken) { $body += @{ cluster = $cluster; region = $zone; listonly = $false; vmids = $($instanceid.Split(",")) projectid = $projectid; } } else { $body += @{ cluster = $cluster; region = $zone; listonly = $false; vmids = $($instanceid.Split(",")) project = $projectid; } } $json = $body | ConvertTo-Json Post-AGMAPIData -endpoint /cloudcredential/$credentialid/discovervm/addvm -body $json } Function New-AGMConsistencyGroup ([string]$clusterid,[string]$applianceid,[string]$hostid,[string]$description,[string]$groupname) { <# .SYNOPSIS Adds new Consistency Group (CG) .EXAMPLE New-AGMConsistencyGroup -clusterid 144292692833 -groupname "prodhost1" -description "this is a CG" -hostid 12344 To learn applianceid, use this command: Get-AGMAppliance and use the clusterid as clusterid. To learn host ID, use this command: Get-AGMHost Once you have created the Consistency Group you can add applications to it with Set-AGMConsistencyGroupMember Once you have created the Consistency Group you can change the name and description with Set-AGMConsistencyGroup .DESCRIPTION A function to add a Consistency Group #> if (($applianceid) -and ($clusterid)) { Get-AGMErrorMessage -messagetoprint "Do not specify both applianceid and clusterid. Only clusterid is needed." return } if ($applianceid) { [string]$clusterid = $applianceid} if (!($clusterid)) { $clusterid = Read-Host "Cluster ID" } if (!($hostid)) { [string]$hostid = Read-Host "Host ID" } if (!($groupname)) { [string]$groupname = Read-Host "Group Name" } # cluster needs to be like: sources":[{"clusterid":"144488110379"},{"clusterid":"143112195179"}] $sources = @() foreach ($cluster in $clusterid.Split(",")) { $sources += [ordered]@{ id = $cluster } } # {"groupname":"testme","description":"description","cluster":{"id":"70194"},"host":{"id":"70631"}} $body = [ordered]@{} $body += [ordered]@{ groupname = $groupname; cluster = $sources; host = [ordered]@{ id = $hostid } } if ($description) { $body += @{ description = $description } } $json = $body | ConvertTo-Json Post-AGMAPIData -endpoint /consistencygroup -body $json } Function New-AGMCredential ([string]$name,[string]$zone,[string]$clusterid,[string]$applianceid,$filename,[string]$projectid,[string]$organizationid,[string]$udsuid) { <# .SYNOPSIS Creates a cloud credential .EXAMPLE This is an example for release 11.0.1 New-AGMCredential -name cred1 -zone australia-southeast1-c -clusterid 144292692833 -filename keyfile.json .EXAMPLE This is an example for release 11.0.2 New-AGMCredential -name cred1 -zone australia-southeast1-c -clusterid 145666187717 -udsuid 1196377951 To learn the Cluster ID, use this command and use the clusterid value: Get-AGMAppliance | select clusterid,name Comma separate the Cluster IDs if you have multiple appliances. Note you cannot specify multiple appliances from release 11.0.2 or higher You can add org IDs with -organizationid To learn the Org IDs, use this command: Get-AGMOrg | select-object id,name Comma separate the Org IDs if you have multiple orgs To add an onvault pool, use -udsuid To learn the udsid use this command: Get-AGMDiskPool -filtervalue pooltype=vault | select-object name,udsuid,@{N='appliancename'; E={$_.cluster.name}},@{N='applianceid'; E={$_.cluster.clusterid}} Ensure the pool exists on all the appliances you are adding the credential to. .DESCRIPTION A function to create cloud credentials #> if (($applianceid) -and ($clusterid)) { Get-AGMErrorMessage -messagetoprint "Do not specify both applianceid and clusterid. Only clusterid is needed." return } if (!($name)) { [string]$name = Read-Host "Credential Name" } if (!($zone)) { [string]$zone = Read-Host "Default zone" } if ($applianceid) { [string]$clusterid = $applianceid} if (!($clusterid)) { [string]$clusterid = Read-Host "Cluster IDs (comma separated)" } if ($filename) { if ( Test-Path $filename ) { $jsonkey = Get-Content -Path $filename -raw $jsonkey = $jsonkey.replace("\n","\\n") $jsonkey = $jsonkey.replace("`n","\n ") $jsonkey = $jsonkey.replace('"','\"') } else { Get-AGMErrorMessage -messagetoprint "The file named $filename could not be found." return } if (!($projectid)) { $jsongrab = Get-Content -Path $filename | ConvertFrom-Json if (!($jsongrab.project_id)) { Get-AGMErrorMessage -messagetoprint "The file named $filename does not contain a valid project ID." return } else { $projectid = $jsongrab.project_id } } } # cluster needs to be like: sources":[{"clusterid":"144488110379"},{"clusterid":"143112195179"}] or "appliance":{"clusterid":"145666187717"} if ($filename) { $sources = @() foreach ($cluster in $clusterid.Split(",")) { $sources += [ordered]@{ clusterid = $cluster } } } else { if ($clusterid.Split(",").count -gt 1) { Get-AGMErrorMessage -messagetoprint "From release 11.0.2 and higher please specify only one appliance at a time" return } $clusterdetails += [ordered]@{ clusterid = $clusterid } } $orglist = @() if ($organizationid) { foreach ($org in $organizationid.Split(",")) { $orglist += [ordered]@{ id = $org } } } $body = [ordered]@{} $body += [ordered]@{ name = $name; cloudtype = "GCP"; region = $zone; endpoint = ""; orglist = $orglist } if ($sources) { $body += [ordered]@{ $projectid = $projectid } $body += [ordered]@{ sources = $sources } } if ($clusterdetails) { $body += [ordered]@{ appliance = $clusterdetails } } if ($udsuid) { $body += [ordered]@{ vault_udsuid = $udsuid } } $json = $body | ConvertTo-Json -compress # this section is post editing the JSON to add in the credential. Ideally we should do this using a PS Object rather than an edit like this. if ($jsonkey) { $json = $json.Substring(0,$json.Length-1) $json = $json + ',"credential":"' + $jsonkey +'"}' } # first we test it $testcredential = Post-AGMAPIData -endpoint /cloudcredential/testconnection -body $json if ($testcredential.errors) { $testcredential return } Post-AGMAPIData -endpoint /cloudcredential -body $json return } Function New-AGMHost ([string]$clusterid,[string]$applianceid,[string]$hostname,[string]$friendlyname,[string]$description,[string]$ipaddress,[string]$alternateip,[string]$hosttype,[string]$organizationid,[string]$secret) { <# .SYNOPSIS Adds new Hosts .EXAMPLE New-AGMHost -clusterid 144292692833 -hostname "prodhost1" -ipaddress "10.0.0.1" Adds Host with name prodhost1 and IP address 10.0.0.1 to specified appliance .EXAMPLE New-AGMHost -clusterid "143112195179,144488110379" -hostname "prodhost1" -ipaddress "10.0.0.1" -friendlyname "mainprod" -description "this is prod, be nice" -alternateip "20.0.0.1,30.0.0.1" Adds Host with name prodhost1 and IP address 10.0.0.1 to two specified appliances, with a friendlyname, text description and two alternate IPs. To learn applianceid, use this command: Get-AGMAppliance and use the clusterid as clusterid. If you have multiple clusterids, comma separate them alternateip needs to be a comma separated list of IPs .DESCRIPTION A function to add Hosts #> if (($applianceid) -and ($clusterid)) { Get-AGMErrorMessage -messagetoprint "Do not specify both applianceid and clusterid. Only clusterid is needed." return } if ($applianceid) { [string]$clusterid = $applianceid} if (!($clusterid)) { $clusterid = Read-Host "Cluster ID" } $clustergrab = Get-AGMAppliance -filtervalue clusterid=$clusterid if ($clustergrab.count -eq 0) { Get-AGMErrorMessage -messagetoprint "Clusterid $clusterid could not be found. Validate clusterid with Get-AGMAppliance" return } if (!($hostname)) { [string]$hostname = Read-Host "Host name" } if (!($ipaddress)) { [string]$ipaddress = Read-Host "IP Address" } if (!($hostype)) { $hosttype = "generic" } # cluster needs to be like: sources":[{"clusterid":"144488110379"},{"clusterid":"143112195179"}] $sources = @() foreach ($cluster in $clusterid.Split(",")) { $sources += [ordered]@{ clusterid = $cluster } } if ($organizationid) { $orglist = @() foreach ($org in $organizationid.Split(",")) { $orglist += [ordered]@{ id = $org } } } # alternate IP format needs to be like: "alternateip":["10.20.0.1","10.30.0.1"], if ($alternateip) { $alternateipaddresses = @( $($alternateip.Split(",")) ) } else { $alternateipaddresses = @() } $udsagent = [ordered]@{} if ($secret) { $udsagent += [ordered]@{ shared_secret = $secret } } $body = [ordered]@{} $body += [ordered]@{ hosttype = $hosttype; hostname = $hostname; ipaddress = $ipaddress; alternateip = $alternateipaddresses; sources = $sources; } if ($orglist) { $body += @{ orglist = $orglist } } if ($description) { $body += @{ description = $description } } if ($friendlyname) { $body += @{ friendlypath = $friendlyname } } if ($secret) { $body += @{ udsagent = $udsagent } } $json = $body | ConvertTo-Json -compress Post-AGMAPIData -endpoint /host -body $json } Function New-AGMMount ([string]$imageid,[string]$targethostid,[string]$jsonbody,[string]$label) { <# .SYNOPSIS Mounts an Image .EXAMPLE New-AGMMount -imageid 1234 -targethostid 5678 Mounts image ID 1234 to target host with ID 5678 .EXAMPLE New-AGMMount -imageid 53776703 -jsonbody '{"@type":"mountRest","label":"test mount","host":{"id":"43673548"},"poweronvm":false,"migratevm":false}' Mounts image ID 53776703 to target host with ID 43673548 with Label "test mount". The jsonbody field needs to be well formed JSON. You can get this by running a mount job in the AGM GUI and then immediately displaying the audit log with: Get-AGMAudit -filtervalue "command~POST https" -limit 1 -sort id:desc .DESCRIPTION A function to mount an Image #> if (!($imageid)) { [string]$imageid = Read-Host "ImageID to mount" } if ( (!($jsonbody)) -and (!($targethostid)) ) { [string]$targethostid = Read-Host "Target host ID to mount $imageid to" if (!($label)) { [string]$label = Read-Host "Label to apply to newly mounted image" } } if ($targethostid) { $body = @{ label = $label; host = @{id=$targethostid} } $jsonbody = $body | ConvertTo-Json } Post-AGMAPIData -endpoint /backup/$imageid/mount -body $jsonbody } Function New-AGMSLA ([string]$appid,[string]$slpid,[string]$sltid,[string]$jsonbody,[string]$scheduler) { <# .SYNOPSIS Creates an SLA .EXAMPLE New-AGMSLA -appid 1234 -sltid 5678 -slpid 9012 -scheduler disabled Creates a new SLA using APPID, SLT ID and SLP ID with scheduler disabled. Details about the new SLA will be returned. The scheduler is disabled so options can be set. You can enable the scheduler with Set-AGMSLA If no options are needed, you don't need to specify scheduler state .DESCRIPTION A function to create an SLA #> if (($id) -and (!($appid)) ) { $appid = $id } if (!($sltid)) { $sltid = Read-Host "SLT ID" } if (!($slpid)) { $slpid = Read-Host "SLP ID" } if (!($jsonbody)) { $application = New-Object -TypeName psobject $application | Add-Member -MemberType NoteProperty -Name id -Value $appid $slp = New-Object -TypeName psobject $slp | Add-Member -MemberType NoteProperty -Name id -Value $slpid $slt = New-Object -TypeName psobject $slt | Add-Member -MemberType NoteProperty -Name id -Value $sltid $body = New-Object -TypeName psobject $body | Add-Member -MemberType NoteProperty -name application -Value $application if (!($scheduler)) { $body | Add-Member -MemberType NoteProperty -Name scheduleoff -Value "false" } if ($scheduler.ToLower() -eq "enable") { $body | Add-Member -MemberType NoteProperty -Name scheduleoff -Value "false" } if ($scheduler.ToLower() -eq "disable") { $body | Add-Member -MemberType NoteProperty -Name scheduleoff -Value "true" } $body | Add-Member -MemberType NoteProperty -name slp -Value $slp $body | Add-Member -MemberType NoteProperty -name slt -Value $slt $jsonbody = $body | ConvertTo-Json } Post-AGMAPIData -endpoint /sla -body $jsonbody } Function New-AGMUser ([string]$name,[string]$timezone,[string]$rolelist,[string]$orglist) { <# .SYNOPSIS Creates a User .EXAMPLE New-AGMUser -name "user@user.user" -rolelist "2,3" -orglist "4,5" Creates a new user .DESCRIPTION A function to create a User #> if (!($name)) { Get-AGMErrorMessage -messagetoprint "Specify a username in email format with -name" return } if ($AGMToken) { if ($name -notlike "*@*") { Get-AGMErrorMessage -messagetoprint "Specify a username in email format with -name" return } } if (!($rolelist)) { Get-AGMErrorMessage -messagetoprint "Specify a comma separated rolelist with -rolelist" return } if ($rolelist) { $rolebody = @() foreach ($role in $rolelist.Split(",")) { $rolebody += New-Object -TypeName psobject -Property @{id="$role"} } } if ($orglist) { $orgbody = @() foreach ($org in $orglist.Split(",")) { $orgbody += New-Object -TypeName psobject -Property @{id="$org"} } } $body = [ordered]@{ name = $name; dataaccesslevel = "0"; timezone = $timezone; rolelist = $rolebody orglist = $orgbody } $jsonbody = $body | ConvertTo-Json Post-AGMAPIData -endpoint /user -body $jsonbody } <# .SYNOPSIS Discover VMWare VMs through AGM .EXAMPLE New-AGMVMDiscovery -vCenterId 6880886 #> function New-AGMVMDiscovery { [CmdletBinding()] param ( [Parameter(Mandatory)] [int] $vCenterId ) Get-AGMAPIData -endpoint "/host/$vCenterId/discovervm" } <# .SYNOPSIS Create a new application for a VMWare VM. .EXAMPLE New-AGMVMApp -vCenterId 7550156 -Cluster 6019 -ClusterName cluster_foo -VmUuids ["91cd1ae2-9fbe-16bf-de71-f1577ab0a1b3"] #> function New-AGMVMApp { [CmdletBinding()] param ( # The `id` of the vCenter host, you can find the `id` by `(Get-AGMHost -filtervalue "isvcenterhost=true") | Select-Object id,name` [Parameter(Mandatory = $true)] [int] $vCenterId, # The `id` of an appliance, it is NOT the `appliance_id`, you can get the appliance by `Get-AGMAppliance` [Parameter(Mandatory = $true)] [int] $Cluster, # The `clustername` of a cluster, you can get the cluster name by `Get-AGMClusterName -vCenterId <your-vcenter-id>` [Parameter(Mandatory = $true)] [string] $ClusterName, # The UUIDs of those VMs to be protected, UUIDs are included in the response of `New-AGMVMDiscovery` [Parameter(Mandatory = $true)] [string[]] $VmUuids ) $body = [ordered]@{ cluster=$Cluster; addvms=$true; vms=$VmUuids; } $json = $body | ConvertTo-Json Write-Verbose "New-AGMVMApp" Write-Verbose "/host/$vCenterId/host/$ClusterName/addvms" Write-Verbose $json Post-AGMAPIData -endpoint "/host/$vCenterId/host/$ClusterName/addvms" -body $json } |