Powershell script while writing to AWS Cloudwatch throws error - Write-CWMetricData : - powershell

We are using Microsoft HPC (High performance computing). When a job is running, I want to see various HPC metrics and publish them onto AWS Cloudwatch. Below is the script that was on AWS site. Entire script runs fine but the last line which tries to write to Cloudwatch fails.
Did anyone get this error?
Write-CWMetricData : A WebException with status NameResolutionFailure was thrown.
At D:\temp\HPCMetricstest.ps1:81 char:1
+ Write-CWMetricData -Namespace "HPC Cluster Metrics" -MetricData $m1,
$m2, $m3, $ ...
+ CategoryInfo : InvalidOperation:
(Amazon.PowerShe...etricDataCmdlet:WriteCWMetricDataCmdlet) [Write-CWM
etricData], InvalidOperationException
+ FullyQualifiedErrorId :mazon.Runtime.AmazonServiceException,Amazon.PowerShell.Cmdlets.CW.WriteCWMetricDataCmdl
et
#
# This PowerShell script computes metrics on the head node of an HPC
Pack cluster and publishes them to Amazon CloudWatch
#
# It must be called with the current region and stack name
# Properties of HPC Nod: NetBiosName, HealthState, State, Groups
[CmdletBinding()]
param(
[Parameter(Mandatory=$True,Position=1)]
[string]$Region,
[Parameter(Mandatory=$True,Position=2)]
[string]$Stack
)
Add-PSSnapIn Microsoft.HPC
Import-Module AWSPowerShell
$jobs = (Get-HpcJob -State Queued, Running -ErrorAction SilentlyContinue)
$tasks = ($jobs | Get-HpcTask -State Running, Queued -ErrorAction SilentlyContinue)
$nodes = (Get-HpcNode -GroupName ComputeNodes -State Online)
$jobCount = $jobs.Count
$taskCount = $task.Count
$coreHours = ($tasks | % { $_.Runtime.TotalHours * $_.MinCores } |
Measure-Object -Sum | Select-Object -ExpandProperty Sum)
$nodeCount = $nodes.Count
$coresPerMachine = ($nodes | Measure-Object -Property SubscribedCores -Average | Select-Object -ExpandProperty Average)
Write-Host "Cores per machine basam " $coresPerMachine
$machineHours = [System.Math]::Ceiling($coreHours / $coresPerMachine)
$globalHours = [System.Math]::Ceiling($machineHours / $nodeCount)
Function CreateMetric
{
param([string]$Name, [string]$Unit="Count", [string]$Value="0",
[string]$StackId, [System.DateTime]$When = (Get-
Date).ToUniversalTime())
$dim = New-Object Amazon.CloudWatch.Model.Dimension
$dim.Name = "StackId"
$dim.Value = $StackId
$dat = New-Object Amazon.CloudWatch.Model.MetricDatum
$dat.Timestamp = $When
$dat.MetricName = $Name
$dat.Unit = $Unit
$dat.Value = $Value
#Write-Host $dat.MetricName $dat.Value $dat.Unit $dat.Timestamp
$dat.Dimensions = New-Object -TypeName System.Collections.Generic.List[Amazon.CloudWatch.Model.Dimension]
$dat.Dimensions.Add($dim)
$dat
}
$now = (Get-Date).ToUniversalTime()
$m1 = (CreateMetric -Name "Job Count" -Value "$jobCount" -StackId
$Stack -When $now)
$m2 = (CreateMetric -Name "Task Count" -Value "$taskCount" -StackId
$Stack -When $now)
$m3 = (CreateMetric -Name "Core Hours" -Value "$coreHours" -StackId
$Stack -When $now)
$m4 = (CreateMetric -Name "Node Count" -Value "$nodeCount" -StackId
$Stack -When $now)
$m5 = (CreateMetric -Name "Cores Per Machine" -Value
"$coresPerMachine" -StackId $Stack -When $now)
$m6 = (CreateMetric -Name "Machine Hours" -Value "$machineHours" -
StackId $Stack -When $now)
$m7 = (CreateMetric -Name "Global Hours" -Value "$globalHours" -
StackId $Stack -When $now)
#Next line I am getting issue
Write-CWMetricData -Namespace "HPC Cluster Metrics" -MetricData
$m1, $m2, $m3, $m4, $m5, $m6, $m7 -Region $Region

In the AWS Tools for PowerShell, "A WebException with status NameResolutionFailure was thrown." often means that you've specified the region incorrectly. This is because the region is used to resolve DNS for the backing web service you're trying to hit, in this case the CloudWatch service for your given region.
See the documentation for a list of valid regions, or comment here with the region you attempted to use and we can help you pick the right one.
Further Reading
AWS PowerShell Documentation - Specifying AWS Regions

Related

Get-AzKeyVaultSecret -VaultName..... | Name or service not known

I have a pipeline in which i calling a power-shell script which copy the azure keyvault secrets from one key-vault to another keyvault.
Here's the powershell script:
$SecretNames = "api-gateway--jwt-public-key",
"authentication-service--jwt-private-key",
"user-management--pen-password",
"user-management--stripe-secret-key"
$sourceVaultName="fdevcuskv03"
$destVaultName="fdevcuskv04"
for (($i = 0); $i -lt $SecretNames.Count; $i++)
{
$sourceSecretName = "$($SecretNames[$i])"
$destSecretName = "$($SecretNames[$i])"
$Getvalue=(Get-AzKeyVaultSecret -VaultName $sourceVaultName -Name $sourceSecretName).SecretValue
Write-Host "Copying $sourceSecretName Value To $destSecretName"
Set-AzKeyVaultSecret -VaultName $destVaultName -Name $destSecretName `
-SecretValue $Getvalue
}
When I run the pipeline, I got this error but this works fine locally.
Here's the error:
Get-AzKeyVaultSecret: /home/vsts/work/1/s/Terraform/Terraform-Scripts/main.ps1:351
Line |
351 | … $Getvalue=(Get-AzKeyVaultSecret -VaultName $sourceVaultName -Name $s …
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
| Name or service not known
I'm bit confused, what i'm doing wrong.
Along with checking that please check also if the case maybe dns resolution issue or invalid dns cache causing the error .
For that please try to give it sleep time and repeat the step.(Also check by dns flush )
Place check azure-powershell issues(github) comment by #placidseven ang set azure keyvault by first checking if dns Is resolved.
foreach(($i = 0); $i -lt $SecretNames.Count; $i++)
{
$sourceSecretName = "$($SecretNames[$i])"
$destSecretName = $sourceSecretName
$Getvalue=(Get-AzKeyVaultSecret -VaultName $sourceVaultName -Name $sourceSecretName).SecretValue
Write-Host "Copying $sourceSecretName Value To $destSecretName"
setSecret
function setSecret{
while (!$secret) {
$DnsCheck = Resolve-DnsName $VaultURI -ErrorAction SilentlyContinue
if (!$DnsCheck) {
write-host "Resolve-DnsName taking time to resolve $vaultName. Keep trying!"
Start-Sleep -Seconds 30
Set-AzKeyVaultSecret -VaultName $destVaultName -Name $destSecretName `
-SecretValue $Getvalue -ErrorAction SilentlyContinue
}
}
$secret = Set-AzKeyVaultSecret -VaultName $destVaultName -Name $destSecretName `
-SecretValue $Getvalue -ErrorAction SilentlyContinue
setSecret
}
}
Reference: Set-AzureKeyVaultSecret does not recognize vaultName · GitHub

Creating AutoShutdown Policy with Azure VM with Powershell

I am trying to create an auto shutdown policy with Powershell for my Azure VM, but keep running into this error:
New-AzureRmResource : MissingRequiredProperty : Missing required property TargetResourceId.
At C:\Users\home\Documents\CreateAzureVM.ps1:167 char:1
+ New-AzureRmResource -Location $Loc -ResourceId $ScheduledShutdownReso ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : CloseError: (:) [New-AzureRmResource], ErrorResponseMessageException
+ FullyQualifiedErrorId : MissingRequiredProperty,Microsoft.Azure.Commands.ResourceManager.Cmdlets.Implementation.NewAzureResourceCmdlet
I am at a lost on how to fix this error, this is my script piece so far:
$SubscriptionId = $AzContext.Context.Subscription.Id;
$VMResourceId = (Get-AzureRmVM).id
$ScheduledShutdownResourceId = "/subscriptions/$SubscriptionId/resourceGroups/$RSGName/providers/microsoft.devtestlab/schedules/shutdown-computevm-$VMName"
$Properties = #{}
$Properties.Add('status', 'Enabled')
$Properties.Add('taskType', 'ComputeVmShutdownTask')
$Properties.Add('dailyRecurrence', #{'time'= 1159})
$Properties.Add('timeZoneId', "Eastern Standard Time")
$Properties.Add('notificationSettings', #{status='Disabled'; timeInMinutes=15})
$Properties.Add('targetResourceId', $VMResourceId)
#Error
New-AzureRmResource -Location $Loc -ResourceId $ScheduledShutdownResourceId -Properties $Properties -Force
The cause:
This script $VMResourceId = (Get-AzureRmVM).id is not for a specific VM. You should get a specific VM.
Try to use following Powershell scripts:
$SubscriptionId = $AzContext.Context.Subscription.Id
$VM = Get-AzureRmVM -ResourceGroupName $RGName -Name VMName
$VMResourceId = $VM.Id
$ScheduledShutdownResourceId = "/subscriptions/$SubscriptionId/resourceGroups/wayneVMRG/providers/microsoft.devtestlab/schedules/shutdown-computevm-$VMName"
$Properties = #{}
$Properties.Add('status', 'Enabled')
$Properties.Add('taskType', 'ComputeVmShutdownTask')
$Properties.Add('dailyRecurrence', #{'time'= 1159})
$Properties.Add('timeZoneId', "Eastern Standard Time")
$Properties.Add('notificationSettings', #{status='Disabled'; timeInMinutes=15})
$Properties.Add('targetResourceId', $VMResourceId)
#Error
New-AzureRmResource -Location eastus -ResourceId $ScheduledShutdownResourceId -Properties $Properties -Force
Here is the result:
here a loop to read the current configured value for Auto-shutdown of AZ vms (can easy add update/change/set based on Wayne Yang example above)
Example will loop thru many subscription.
:
###################
##:List all subs which are enabled
#$AllSubID = (Get-AzureRmSubscription | Where {$_.State -eq "enabled"}).SubscriptionId
### above might not work depends on account, just get all below.
$AllSubID = (Get-AzureRmSubscription).SubscriptionId
Write-Output "$(Get-Date -format s) :: List of Subscription below"
$AllSubID
$AllVMList = #()
Foreach ($SubID in $AllSubID) {
Select-AzureRmSubscription -Subscriptionid "$SubID"
##list all VMs
$VMs = Get-AzureRmVM
Foreach ($VM in $VMs) {
$VM = New-Object psobject -Property #{`
"Subscriptionid" = $SubID;
"ResourceGroupName" = $VM.ResourceGroupName;
"VMName" = $VM.Name}
$AllVMList += $VM | select Subscriptionid,ResourceGroupName,VMName
}
}
$AllVMList
## Get AutoShutdown info
Foreach ($VM in $AllVMList) {
Write-Output "$(Get-Date -format s) :: VM: $($VM.VMName) :: $($VM.ResourceGroupName) :: $($VM.Subscriptionid)"
$ScheduledShutdownResourceId = "/subscriptions/$($VM.Subscriptionid)/resourceGroups/$($VM.ResourceGroupName)/providers/microsoft.devtestlab/schedules/shutdown-computevm-$($VM.VMName)"
## Write-Output "$ScheduledShutdownResourceId"
$VMShutdownInfo = get-AzureRmResource -ResourceId $ScheduledShutdownResourceId
Write-Output "$(Get-Date -format s) :: VM: $($VM.VMName) :: status: $($VMShutdownInfo.properties.status) ; taskType: $($VMShutdownInfo.properties.taskType) ; timeZoneId: $($VMShutdownInfo.properties.timeZoneId) ; dailyRecurrence: $($VMShutdownInfo.properties.dailyRecurrence) ; "
}
###Done

Powershell : How to get Antivirus product details

We have over 1500 servers. Windows 2003, 2008 and 2012. I have to gather the details of antivirus(Product Name & Version) on these servers.
There could be multiple antivirus product.
I am not sure powershell script will work on 2003 server.
So, far i tried below scripts but not got useful information.
$av = get-wmiobject -class "Win32_Product" -namespace "root\cimv2" `
-computername "." -filter "Name like '%antivirus%'"
Below script is working fine on client operating system.
$wmiQuery = "SELECT * FROM AntiVirusProduct"
$AntivirusProduct = Get-WmiObject -Namespace "root\SecurityCenter2" -Query $wmiQuery #psboundparameters # -ErrorVariable myError -ErrorAction 'SilentlyContinue'
Write-host $AntivirusProduct.displayName
Can anybody advise me on this?
I am trying to get the details of antivirus(Product & Version)
What do i need to do for win server 2003?
You were on the right path, the following Powershell script works.
function Get-AntiVirusProduct {
[CmdletBinding()]
param (
[parameter(ValueFromPipeline=$true, ValueFromPipelineByPropertyName=$true)]
[Alias('name')]
$computername=$env:computername
)
#$AntivirusProducts = Get-WmiObject -Namespace "root\SecurityCenter2" -Query $wmiQuery #psboundparameters # -ErrorVariable myError -ErrorAction 'SilentlyContinue' # did not work
$AntiVirusProducts = Get-WmiObject -Namespace "root\SecurityCenter2" -Class AntiVirusProduct -ComputerName $computername
$ret = #()
foreach($AntiVirusProduct in $AntiVirusProducts){
#Switch to determine the status of antivirus definitions and real-time protection.
#The values in this switch-statement are retrieved from the following website: http://community.kaseya.com/resources/m/knowexch/1020.aspx
switch ($AntiVirusProduct.productState) {
"262144" {$defstatus = "Up to date" ;$rtstatus = "Disabled"}
"262160" {$defstatus = "Out of date" ;$rtstatus = "Disabled"}
"266240" {$defstatus = "Up to date" ;$rtstatus = "Enabled"}
"266256" {$defstatus = "Out of date" ;$rtstatus = "Enabled"}
"393216" {$defstatus = "Up to date" ;$rtstatus = "Disabled"}
"393232" {$defstatus = "Out of date" ;$rtstatus = "Disabled"}
"393488" {$defstatus = "Out of date" ;$rtstatus = "Disabled"}
"397312" {$defstatus = "Up to date" ;$rtstatus = "Enabled"}
"397328" {$defstatus = "Out of date" ;$rtstatus = "Enabled"}
"397584" {$defstatus = "Out of date" ;$rtstatus = "Enabled"}
default {$defstatus = "Unknown" ;$rtstatus = "Unknown"}
}
#Create hash-table for each computer
$ht = #{}
$ht.Computername = $computername
$ht.Name = $AntiVirusProduct.displayName
$ht.'Product GUID' = $AntiVirusProduct.instanceGuid
$ht.'Product Executable' = $AntiVirusProduct.pathToSignedProductExe
$ht.'Reporting Exe' = $AntiVirusProduct.pathToSignedReportingExe
$ht.'Definition Status' = $defstatus
$ht.'Real-time Protection Status' = $rtstatus
#Create a new object for each computer
$ret += New-Object -TypeName PSObject -Property $ht
}
Return $ret
}
Get-AntiVirusProduct
Output:
Product GUID : {B0D0C4F4-7F0B-0434-B825-1213C45DAE01}
Name : CylancePROTECT
Real-time Protection Status : Enabled
Computername : HOSTNAME
Product Executable : C:\Program Files\Cylance\Desktop\CylanceSvc.exe
Reporting Exe : C:\Program Files\Cylance\Desktop\CylanceSvc.exe
Definition Status : Up to date
Product GUID : {D68DDC3A-831F-4fae-9E44-DA132C1ACF46}
Name : Windows Defender
Real-time Protection Status : Unknown
Computername : HOSTNAME
Product Executable : windowsdefender://
Reporting Exe : %ProgramFiles%\Windows Defender\MsMpeng.exe
Definition Status : Unknown
Instead of relying on running processes, you could query the registry :
$computerList = "localhost", "localhost"
$filter = "antivirus"
$results = #()
foreach($computerName in $computerList) {
$hive = [Microsoft.Win32.RegistryKey]::OpenRemoteBaseKey([Microsoft.Win32.RegistryHive]::LocalMachine, $computerName)
$regPathList = "SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall",
"SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall"
foreach($regPath in $regPathList) {
if($key = $hive.OpenSubKey($regPath)) {
if($subkeyNames = $key.GetSubKeyNames()) {
foreach($subkeyName in $subkeyNames) {
$productKey = $key.OpenSubKey($subkeyName)
$productName = $productKey.GetValue("DisplayName")
$productVersion = $productKey.GetValue("DisplayVersion")
$productComments = $productKey.GetValue("Comments")
if(($productName -match $filter) -or ($productComments -match $filter)) {
$resultObj = [PSCustomObject]#{
Host = $computerName
Product = $productName
Version = $productVersion
Comments = $productComments
}
$results += $resultObj
}
}
}
}
$key.Close()
}
}
$results | ft -au
Example output :
Host Product Version Comments
---- ------- ------- --------
localhost Avast Free Antivirus 10.4.2233
localhost Avast Free Antivirus 10.4.2233
Would this work for you? It's written in PowerShell v2, so if you have that installed on your 2003 servers, it will run on all the servers. This code will give you a CSV of this data from whichever machines run the script that have a service with the description including the word "virus" (which I thought better than "antivirus" because some services use "anti-virus" instead). If they all have access to a shared resource, you can prepend that shared resource directory to the $Filename variable and it will name each report starting with that computer's name and dump your reports there.
invoke-command -computername Server01, Server02 -filepath c:\Scripts\get_av_info.ps1
Assuming the script is saved as c:\Scripts\get_av_info.ps1, that should run it on whatever machines you specify, or if you have a CSV of all the machines you want to run the script, ForEach it. I didn't try this, so I can't verify the remote invoking.
$Date = (Get-Date).ToString('yyyy-MM-dd')
$localhost = $env:computername
$Filename = "C:\" + $localhost + "_" + $Date + "_AV_FileInfo.csv"
$AV = get-process | ?{$_.Description -like "*virus*"}
$Process = ForEach($a in $AV){
$ID = $($a.Id)
get-process -Id $ID -FileVersionInfo
}
$Process | select "CompanyName","FileBuildPart","FileDescription","FileName","FileVersion","ProductName","ProductPrivatePart","ProductVersion","SpecialBuild" | Export-Csv $Filename -NoTypeInformation
There are a LOT of options, I just picked ones I thought you'd want. You could probably also combine the reports to one by adding a shared resource to the Filename and having it -Append, but you would run the risk of multiple servers trying to write to the file at the same time and failing to report at all.
You'll need to refine your results, of course. If you don't change anything, any machine where you run this will just drop a CSV called "COMPUTERNAME_DATE_AV_FileInfo.csv" at the root of it's C:\ drive.

Import-vApp throwin Line 157: Duplicate element 'AddressOnParent' error

I am trying to deploy an OVA file using powershell script. I found a script from internet and modified it a little bit and execute. During execution at Import-VApp command i am seeing this error: Import-VApp Line 157: Duplicate element 'AddressOnParent'.
I am able to deploy the OVA manually. But thru this script, i am seeing this error. Any help would be appreciated.
Please find my powershell script below. (keeping only important script below, per suggestion).
param(
)
#---- Custom OVA Properties ::> START <:: ----- #
$vAPPPropertyId_ip4enable = "IPv4 Enable"
$vAPP_ip4enable = "True"
$vAPPPropertyId_ip4address = "IPv4 Address"
$vAPP_ip4address = "10.51.98.20"
$vAPPPropertyId_ip4netmask = "IPv4 Netmask"
$vAPP_ip4netmask = "255.255.255.0"
$vAPPPropertyId_ip4gateway = "Ipv4 Gateway"
$vAPP_ip4gateway = "10.51.98.1"
$vAPPPropertyId_ip6enable = "Ipv6 Enable"
$vAPP_ip6enable = "False"
#$vAPPPropertyId_ip6address = "IPv6 Address"
#$vAPP_ip6address = ""
#$vAPPPropertyId_ip6gateway = "IPv6 Gateway"
#$vAPP_ip6gateway = ""
$vAPP_defaultRouteKey = 1
$vAPP_defaultRouteCmd = ""
#---- Custom OVA Properties ::> END <:: ----- #
$rp = Get-ResourcePool -name $resourcePool
Write-Host " Resoure Pool = $rp"
$cluster = $rp.ExtensionData.Owner
$vhost = (Get-Cluster -Id $cluster).ExtensionData.Host[0]
Write-Host " VHost = $vhost "
$VMHost = Get-VMHost -Id $vhost
Write-Host " VMHost = $VMHost "
if ($PortProfile -ne "")
{$PortgroupId = Get-VirtualPortGroup -Name $PortProfile -Distributed -VMHost (Get-VMHost $VMHost)}
Write-host "PortGroup = $PortgroupId"
Write-Host "Importing VApp .... "
$ovalocation = "C:\Script\s42700x8_1_1_a2.ova"
Write-Host "vAppName = $vAppName"
$vms = Import-VApp -Source $ovalocation -Name $vAppName -VMHost $VMHost #-Location $rp -Datastore $ds
#$vms = Import-VApp -Source $ovalocation -Name $vAppName -Location $rp -VMHost $VMHost -Datastore $ds
}
finally {
disconnect-VIServer -Confirm:$false
}
Output looks like this:
PS C:\Users\Administrator> C:\Script\OvaTestFile2.ps1
9/22/2014 3:23:58 AM Import-VApp Line 157: Duplicate element 'AddressOnParent'.

clone vm change network identity

I'm trying to script (powershell/powercli) the cloning of our QA environment (261 servers).
Basically I want to make a new copy of each server just changing the VM name, the hostname, and the IP address. Ideally I'd want the new clone on the domain (90% of them are Windows OS). And many of my servers have many large hard drives that won't all fit on one datastore so I have to be able to clone to multiple datastores.
I started off with New-VM for the servers that were small enough to fit on one datastore, but OSCustomization only works about 30% of the time. The rest of the time I have to login to Windows and manually remove from the domain to rename the hostname. Most of the time Set-OSCustomizationNicMapping works But specifying -Domain -DomainUsername/Password never works (at best it renames the server and puts in the "domain-name" workgroup but it never joins it to the domain).
To workaround the multidatastore issue I discovered $vm.ExtensionData.CloneVM using VMWare.Vim.VirtualMachineRelocateSpec to specify which hard drives go to which datastores and that works great, but I don't know how to customize the hostname or NIC settings.
So the basic requirements are: clone to multiple datastores changing hostname and IP settings. Does anyone have any recommendations or solutions?
Here's some of my code snippets:
Setting up the OSCustomizationSpec for New-VM
$spec = New-OSCustomizationSpec -Name "PowerCLI Scripting for $NewHostName" -Spec "PowerCLI Scripting" -WhatIf:$False
Set-OSCustomizationSpec $spec -Workgroup "WORKGROUP" -DomainUsername "qajoin#qa.company.com" -DomainPassword (Get-Password -Username "qa\qajoin") -ProductKey $ProductKey -AdminPassword (Get-Password $Script:LuserName) | Out-Null
Get-OSCustomizationSpec "PowerCLI Scripting for $NewHostName" `
| Get-OSCustomizationNicMapping `
| Set-OSCustomizationNicMapping `
-IPMode:UseStaticIP `
-IPAddress $NewIPAddress `
-SubnetMask "255.255.248.0" `
-DNS "10.26.40.115","10.26.40.116" `
-DefaultGateway $NewDFGW | Out-Null
The New-VM command:
$VM = New-VM -VMHost $VMHost -VM $Hostname -Name $NewHostName -Description "$Description" -OSCustomizationSpec "PowerCLI Scripting for $NewHostName" -Location (Get-Folder -Id $Location) -Datastore $MostFreeSpace -ErrorAction Stop
Here's the multi-datastore clone:
$VMXtargetDatastore = Get-Datastore ($MapInfo | Where-Object {$_.Name -eq "Hard disk 1"}).NewDataStore
#Create an empty CloneSpec
$spec = New-Object VMware.Vim.VirtualMachineCloneSpec
$spec.Template = $false
$spec.PowerOn = $false
#Create a RelocateSpec (datastore is target for .vmx)
$spec.Location = New-Object VMware.Vim.VirtualMachineRelocateSpec
$spec.Location.Datastore = $targetDatastore.ExtensionData.MoRef
#For each disk in the current vm
# create a new DiskLocator spec
# populate the datastore and diskid from the current harddisk
# add the spec to RelocateSpec from above
Get-HardDisk -VM $Origvm | %{
$disk = New-Object VMware.Vim.VirtualMachineRelocateSpecDiskLocator
$disk.diskId = $_.ExtensionData.Key #2001,2002,2003,...
$DiskLabel = $_.ExtensionData.DeviceInfo.Label
#$disk.datastore = $_.ExtensionData.Backing.Datastore #type=datastore value=datastore-2790
$dsname = ($MapInfo | Where-Object {$_.Name -eq $DiskLabel}).NewDataStore
$ds = Get-Datastore -Name $dsname
$disk.datastore = $ds.id
$spec.Location.Disk += $disk
}
$CustSpec = New-Object VMware.Vim.CustomizationSpec
$origvm.ExtensionData.CloneVM((Get-Folder -Id $folder).ExtensionData.MoRef, $targetName, $spec)
I'm guessing the next step using the ExtensionData.CloneVM method is to declare a new object of CustomizationIdentitySettings but the documentation (http://pubs.vmware.com/vi3/sdk/ReferenceGuide/vim.vm.customization.IdentitySettings.html) that I could find isn't really helpful (probably because the settings vary by OS?) and then add that object to my $spec object.
Same would go for OSCustomizationNicMapping (http://www.vmware.com/support/developer/PowerCLI/PowerCLI41U1/html/OSCustomizationNicMapping.html) but I can't suss enough information out of the pubs to figure out how to build my $spec object.
Can't you copy to an isolated environment? Just build a set of extra (isolated) VLANs and copy all VMs, keep IP/Names, only switch the VLAN at the VM level.
I finally found this page: http://www.vmdev.info/?p=202
I started with the example they show and it worked, so I kept adding in CloneSpec fields until I got what I wanted:
$nicMaparray = #()
$FirstNic = New-Object VMware.Vim.CustomizationAdapterMapping
$FirstNic.adapter = New-Object VMware.Vim.CustomizationIPSettings
$FirstNic.adapter.dnsDomain = $domain
$FirstNic.adapter.dnsServerList = "10.26.40.115","10.26.40.116"
$FirstNic.adapter.gateway = $DefGW
$FirstNic.adapter.ip = New-Object Vmware.Vim.CustomizationFixedIp
$FirstNic.adapter.ip.IpAddress = $NewIP
$FirstNic.adapter.subnetMask = "255.255.248.0"
$nicMaparray += $FirstNic
$folderobj = $origvm.parent
$vm = Get-VM $sourceName | Get-View
$cloneName = $targetName
$cloneFolder = Convert-PathToFolderObject -FolderPath $folderpath
$cloneSpec = new-object Vmware.Vim.VirtualMachineCloneSpec
$cloneSpec.Location = new-object Vmware.Vim.VirtualMachineRelocateSpec
$cloneSpec.Location.Host = (Random(Get-VMHost | Where {$_.Name -like "*esxiqa*"}) | get-view).MoRef
$targetDatastore = ($MapInfo | Where-Object {$_.Name -eq "Hard disk 1"}).NewDataStore
$cloneSpec.Location.Datastore = (Get-Datastore $targetDatastore | get-view).MoRef
$cloneSpec.customization = New-Object VMware.Vim.CustomizationSpec
$cloneSpec.customization.globalIPSettings = New-Object VMware.Vim.CustomizationGlobalIPSettings
$cloneSpec.customization.globalIPSettings.dnsServerList = "10.26.40.115","10.26.40.116"
$cloneSpec.customization.identity = New-Object VMware.Vim.CustomizationSysprep
# $spec.customization.identity.guiRunOnce = New-Object VMware.Vim.CustomizationGuiRunOnce
$cloneSpec.customization.identity.guiUnattended = New-Object VMware.Vim.CustomizationGuiUnattended
$cloneSpec.customization.identity.guiUnattended.autoLogonCount = 0
$cloneSpec.customization.identity.guiUnattended.password = New-Object VMware.Vim.CustomizationPassword
$cloneSpec.customization.identity.guiUnattended.password.plainText = $true
$cloneSpec.customization.identity.guiUnattended.password.value = Get-Password -Username "Administrator"
$cloneSpec.customization.identity.identification = New-Object VMware.Vim.CustomizationIdentification
$cloneSpec.customization.identity.identification.joinWorkgroup = "WORKGROUP"
# $spec.customization.identity.licenseFilePrintData = $null
$cloneSpec.customization.identity.userData = New-Object VMware.Vim.CustomizationUserData
$cloneSpec.customization.identity.userData.computerName = New-Object VMware.Vim.CustomizationFixedName
$cloneSpec.customization.identity.userData.computerName.name = $cloneName
$cloneSpec.customization.identity.userData.productID = $ProductKey
$cloneSpec.customization.nicSettingMap = $nicMaparray
#nicMaparray build above
# $cloneSpec.customization.options = $null
$cloneSpec.powerOn = $true
Get-HardDisk -VM $sourceName | %{
$disk = New-Object VMware.Vim.VirtualMachineRelocateSpecDiskLocator
$disk.diskId = $_.ExtensionData.Key #2001,2002,2003,...
$DiskLabel = $_.ExtensionData.DeviceInfo.Label
$dsname = ($MapInfo | Where-Object {$_.Name -eq $DiskLabel}).NewDataStore
$ds = Get-Datastore -Name $dsname
$disk.datastore = $ds.id
$cloneSpec.Location.Disk += $disk
}
Write-Verbose "Cloning $sourceName"
try
{
$vm.CloneVM( $cloneFolder, $cloneName, $cloneSpec)
return $true
}
catch
{
$_.Exception
return $false
}