Booting from an ISO image using PowerCLI scripts - powershell

How do I make the following script work? Currently I am able to create a new virtual machine in my server. I wish to also load the Windows ISO image and do an unattended installation in the virtual machine. How shall I edit the script to make this work?
# Virtual Center Details
$server_address = "xxxxx"
$username = "xxxxx"
$password = "xxxxx"
$iso = "WINXP_X86_SP3_CD.ISO"
Get-VIServer -Server $server_address -Protocol https -User $username -Password $password
foreach ($vmm in $array)
{
$vmm = "VirtualMachine"
New-VM -name $vmm -DiskMB 20000 -memoryMB 2000
Get-VM $vmm | Get-CDDrive | Set-CDDrive -IsoPath $iso -StartConnected $true -Confirm:$false
$value = "5000"
$vm = Get-VM $vmname | Get-View
$vmConfigSpec = New-Object VMware.Vim.VirtualMachineConfigSpec
$vmConfigSpec.BootOptions = New-Object VMware.Vim.VirtualMachineBootOptions
$vmConfigSpec.BootOptions.BootDelay = $value
$vm.ReconfigVM_Task($vmConfigSpec)
Start-vm -vm $vmname
}

my issue is with the ISO PATH image. I am getting the error "Invalid datastore format"
You are specifying isopath using IsoPath parameter, which is the datastore path to the ISO, not simply the ISO name. From your code you are not indicating any datastore.
The syntax for a datastore path is:
"[yourdatastore] IsoFolder\$iso"
Example got from PowerCLI reference online:
$cd = New-CDDrive -VM $vm -ISOPath "[sof-20666-esx:storage1] ISO\testISO.iso"
Set-CDDrive -CD $cd -StartConnected -Connected

Related

How to pass the body using powershell routes.jason

I'm trying to expose an endpoint using RestPS routes in powershell. I was able to expose it and run a custom PS script when an endpoint (http://localhost:8080/scan) is hit.
How do we pass body through routes & based on that value I need to execute the custom script.
RestPSroutes.json - Example
{
"RequestType": "GET",
"RequestURL": "/scan",
"RequestCommand": "C:/RR/api-compliance.ps1" }
snippet from the above script (api-compliance.ps1) ;
###############
# Setup Creds #
###############
$userID = "****"
$Pass = "*****"
#$Creds = New-Object -TypeName System.Management.Automation.PSCredential -ArgumentList $userID,$Pass
$vCenter = "vCenter01"
$cluster = "Cluster01"
$vmhost = "Host01"
$bl = "Baseline01"
######################
# Connect to vCenter #
######################
Connect-VIServer $VCTRs -user $userID -password $Pass -WarningAction SilentlyContinue -Force
$baseline = Get-Baseline | ? {$_.name -eq $bl}
$baseline | Attach-Baseline -Entity $vmhost -Confirm:$false
Scan-Inventory -Entity $vmhost
Right now we are hardcoding the below values
$vCenter = "vCenter01"
$cluster = "Cluster01"
$vmhost = "Host01"
But we want these to be passed as a request body. Can someone help?
Simply declare parameters $RequestArgs and $Body in the target script/function, and RestPS will automatically pass the appropriate values along as strings:
param(
[string]$RequestArgs,
[string]$Body
)
$RequestArgs.Split('&') |ForEach-Object {
$paramName,$paramValue = $_.Split('=')
Write-Host "Received query parameter ${paramName} with value '$paramValue'"
}

DCOM machine level access and launch permissions via PowerShell

Is it possible to set machine level "My Computer" access and launch permissions from PowerShell?
The equivalent of
DComPerm.exe -ma set name permit level:l,r
DComPerm.exe -ml set name permit level:l,r
I am looking for a solution using PowerShell v 3.0. The target servers are Windows Server 2008 R2 and 2012.
I have found a number of references for setting the DCOM application security settings. However I can't figure out how to set it at the machine or top level.
https://janbk.wordpress.com/2015/03/12/automating-dcom-acl-with-powershell/
Alternative to using DcomPerm.exe and SetAcl.exe in powershell
We have been using WMI to set Launch Permissions.
Refer: https://rkeithhill.wordpress.com/2013/07/25/using-powershell-to-modify-dcom-launch-activation-settings/
This stopped working after windows security patches rolled out (patch #: 4012212, 4012213, and 4012213)
We converted WIM powershell script to use CIM and that took care of setting launch permissions on DCOM objects & works with the security patches. Code is below for reference:
$ComponentName = "TestComponent" #--- change value as needed
$Username = "Username" #--- change value as needed
$Domain = "Domain" #--- change value as needed
# If you already have a CimSession that you used to get the security descriptor, you can leave this line out and use the existing one:
$CimSession = New-CimSession localhost
Grant-DComAccessToUser -ComponentName $ComponentName -Username $Username -Domain $Domain
# Cleanup
$CimSession | Remove-CimSession
function Grant-DComAccessToUser {
param(
[Parameter(Mandatory=$true)][string] $ComponentName,
[Parameter(Mandatory=$true)][string] $Username,
[string] $Domain
)
$DCom = Get-CimInstance -Query "SELECT * from Win32_DCOMApplicationSetting WHERE Description LIKE '$ComponentName%'"
$GetDescriptor = Invoke-CimMethod -InputObject $DCom -MethodName "GetLaunchSecurityDescriptor";
$ExistingDacl = $GetDescriptor.Descriptor.DACL | Where {$_.Trustee.Name -eq $Username}
if ($ExistingDacl)
{
$ExistingDacl.AccessMask = 11
}
else
{
$NewAce = New-DComAccessControlEntry -Domain $Domain -Username $Username
$GetDescriptor.Descriptor.DACL += $NewAce
}
Invoke-CimMethod -InputObject $DCom -MethodName "SetLaunchSecurityDescriptor" -Arguments #{Descriptor=$GetDescriptor.Descriptor};
}
function New-DComAccessControlEntry {
param(
[Parameter(Mandatory=$true)][string] $Username,
[string] $Domain
)
# Create the Win32_Trustee instance
$Trustee = New-Object ciminstance $CimSession.GetClass("root/cimv2", "Win32_Trustee")
$Trustee.Name = $Username
$Trustee.Domain = $Domain
# Create the Win32_ACE instance
$Ace = New-Object ciminstance $CimSession.GetClass("root/cimv2", "Win32_ACE")
$Ace.AceType = [uint32] [System.Security.AccessControl.AceType]::AccessAllowed
$Ace.AccessMask = 11
$Ace.AceFlags = [uint32] [System.Security.AccessControl.AceFlags]::None
$Ace.Trustee = $Trustee
$Ace
}
You can change this script: https://gallery.technet.microsoft.com/scriptcenter/Grant-Revoke-Get-DCOM-22da5b96. It works with application permissions using registry path "HKCR:\AppID\$ApplicationID" and registry keys "AccessPermission", "LaunchPermission".
You should use registry path "HKLM:SOFTWARE\Microsoft\Ole" and registry keys "DefaultAccessPermission", "DefaultLaunchPermission", "MachineAccessRestriction", "MachineLaunchRestriction".
More info in "Configuring Remote DCOM" chapter: https://books.google.ru/books?id=rbpNppFdipkC&pg=PT211&lpg=PT211&dq=dcom+grant+local+launch+permission+powershell&source=bl&ots=5ZfeVca5NA&sig=9lMN_VeymG8cf73KT062QTsWWkc&hl=ru&sa=X&ved=0ahUKEwikn73f6YLcAhVEDSwKHUftCwkQ6AEIfDAI#v=onepage&q&f=true

Changing domain of computer using powercli OSCustomizationSpec

We are trying to automate creation of VMs based on a spread sheet (csv file). These VMs will be based on the template. Template is specified in the sheet. The script works fine and machines are created. However, computer does not join domain. IP and computer name are successfully changed.
Need help in figuring out how to troubleshoot this issue. Following is the snippet used for setting the IP and domain.
New-OSCustomizationSpec -OrgName "Company" -OSType Windows `
-Description $vm.Description -Domain "mydomain" -DomainUsername "domainuser" -DomainPassword "password" `
-ChangeSid -AdminPassword "newpassword" -Name wincli -Type "Persistent" -FullName "Windows Custom Spec"
Get-OSCustomizationNicMapping -OSCustomizationSpec wincli | Set-OSCustomizationNicMapping -Position 1 -IpMode UseStaticIP -IpAddress $vmIP -SubnetMask $vmSubNet -DefaultGateway $vmGateway -Dns $vmDNS1,$vmDNS2 -Confirm:$false
New-OSCustomizationNicMapping –OSCustomizationSpec wincli -Position 2 -IpMode UseStaticIP -IpAddress $vmIP -SubnetMask $vmSubNet -DefaultGateway $vmGateway -Dns $vmDNS1,$vmDNS2 -Confirm:$false
$custom = Get-OSCustomizationSpec -name wincli
$NewVM = New-VM -ResourcePool $resourcePool -Name $vmname -Location $folder -Datastore $datastore -Template $template -OSCustomizationSpec $custom -confirm:$true
Comment from BenH was right on target.
It worked after adding using the format of username as pointed by BenH. (Username: user#domain.xyz.com, domain: domain.xyz.com)

Is there a way to get VMs Operating System name from Hyper-V using powershell?

I'm writing a script on HYPER-V host for getting VMs guest informations. Is there a way to get VMs Operating System name from Hyper-V using powershell?
There are several examples using (Get-WmiObject Win32_OperatingSystem -ComputerName $vmName).name but i should get this information directly from Hyper-V because of domain restrictions.
Also i'm using hyper-v module of powershell but i couldn't see any cmdlets related to OS.
This could be retrieved from guest intrinsic exchange items.
# Filter for parsing XML data
filter Import-CimXml
{
# Create new XML object from input
$CimXml = [Xml]$_
$CimObj = New-Object -TypeName System.Object
# Iterate over the data and pull out just the value name and data for each entry
foreach ($CimProperty in $CimXml.SelectNodes("/INSTANCE/PROPERTY[#NAME='Name']"))
{
$CimObj | Add-Member -MemberType NoteProperty -Name $CimProperty.NAME -Value $CimProperty.VALUE
}
foreach ($CimProperty in $CimXml.SelectNodes("/INSTANCE/PROPERTY[#NAME='Data']"))
{
$CimObj | Add-Member -MemberType NoteProperty -Name $CimProperty.NAME -Value $CimProperty.VALUE
}
# Display output
$CimObj
}
# Prompt for the Hyper-V Server to use
$HyperVServer = Read-Host "Specify the Hyper-V Server to use (enter '.' for the local computer)"
# Prompt for the virtual machine to use
$VMName = Read-Host "Specify the name of the virtual machine"
# Get the virtual machine object
$query = "Select * From Msvm_ComputerSystem Where ElementName='" + $VMName + "'"
$Vm = gwmi -namespace root\virtualization\v2 -query $query -computername $HyperVServer
# Get the KVP Object
$query = "Associators of {$Vm} Where AssocClass=Msvm_SystemDevice ResultClass=Msvm_KvpExchangeComponent"
$Kvp = gwmi -namespace root\virtualization\v2 -query $query -computername $HyperVServer
Write-Host
Write-Host "Guest KVP information for" $VMName
# Filter the results
try {
$Kvp.GuestIntrinsicExchangeItems | Import-CimXml | where Name -eq "OSName"
}
catch {
Write-Host "Not found"
}
From Ben Armstrong’s Virtualization Blog.
Unless you're using SCVMM, Guest OS details are not available via Hyper-V PowerShell cmdlets.
You have to query the Guest itself like you've already found.
I couldn't run t1meless' script on PowerShell version 7.1, because gwmi is deprecated in 7.1, sources MS Docs and GitHub.
I rewrote the script for PS 7.1.
# Script for retrieving Hyper-V Guest Operating System.
# Tested on PowerShell 7.1
# Prompt for the Hyper-V Server to use
$hyper_v_server = Read-Host "Specify the Hyper-V Server to use (enter '.' for the local computer)"
# Prompt for the virtual machine to use
$vm_name = Read-Host "Specify the name of the virtual machine"
# Check if VM exists and is running. This script doesn't work if the VM is stopped.
# Capture error output, source: https://stackoverflow.com/a/66861283/3498768
$vm_not_found = $($vm_state = (Get-VM $vm_name).state) 2>&1
if ($vm_not_found -ne $null) {
Write-Host "$vm_name VM was not found."
exit
}
if ($vm_state -eq "Off") {
Write-Host "Cannot retrieve information of $vm_name. The VM is stopped. Only running VM information can be retrieved."
exit
}
# Get the virtual machine object
$query = "Select * From Msvm_ComputerSystem Where ElementName='" + $vm_name + "'"
$vm = Get-CimInstance -namespace root\virtualization\v2 -query $query -computername $hyper_v_server
# Get associated information
$vm_info = Get-CimAssociatedInstance -InputObject $vm
Write-Host "Guest information for" $vm_name
# Select only required information
$vm_info | Where GuestOperatingSystem |
Select -Property GuestOperatingSystem |
Format-List *

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
}