Add-PSSnapin VMware.* -ErrorAction SilentlyContinue
#instantiate script variables
set-variable -name clustername -scope script
set-variable -name vmhostname -scope script
set-variable -name networklabel -scope script
set-variable -name vcenter -scope script
set-variable -name vmname -scope script
set-variable -name vCPU -scope script
set-variable -name vRAM -scope script
set-variable -name vmdisk2 -scope script
set-variable -name store -scope script
set-variable -name desc -scope script
set-variable -name osid -scope script
#function to prompt for confirmation
function Confirm($strMessage)
{
write-host -foregroundcolor yellow `n $strMessage
$answer = $host.ui.rawui.readkey("NoEcho,IncludeKeyUp")
if ($answer.Character -ine "y")
{
write ""
break
}
write ""
}
#lists our supplied specs
function listspecs{
write-host -foregroundcolor green `n "These are the specs of the new server:"
write-host -foregroundcolor yellow `n`t "Environment:" $script:vcenter
write-host -foregroundcolor yellow `n`t "Server Name:" $script:vmname
write-host -foregroundcolor yellow `n`t "Number of CPUs:" $script:vCPU
write-host -foregroundcolor yellow `n`t "Amount of RAM:" $script:vRAM "GB"
write-host -foregroundcolor yellow `n`t "OS Disk: 64 GB" # 64GB is our standard
write-host -foregroundcolor yellow `n`t "Data Disk:" $script:vmdisk2 "GB"
write-host -foregroundcolor yellow `n`t "Cluster:" $script:clustername
write-host -foregroundcolor yellow `n`t "Network:" $script:networklabel
write-host -foregroundcolor yellow `n`t "Datastore:" $script:store
if($script:osid -eq "winLonghornGuest"){write-host -foregroundcolor yellow `n`t "Installing Windows 2008 x86"}
if($script:osid -eq "winLonghorn64Guest"){write-host -foregroundcolor yellow `n`t "Installing Windows 2008 x64"}
if($script:osid -eq "windows7Server64Guest"){write-host -foregroundcolor yellow `n`t "Installing Windows 2008 R2"}
if($script:osid -eq "winNetEnterpriseGuest"){write-host -foregroundcolor yellow `n`t "Installing Windows 2003 x86"}
if($script:osid -eq "winNetEnterprise64Guest"){write-host -foregroundcolor yellow `n`t "Installing Windows 2003 x64"}
Confirm("Press 'Y' to continue, or any other key to exit...")
}
#prompts for sizing specs of the VM
function getspecs{
$script:vcenter = (read-host `n "vCenter server").tolower()
$script:vmname = (read-host `n "Name of VM").toupper() #I like the name being in caps in vC
$script:desc = (read-host `n "Enter a description for the notes (App, your name, etc)")
[int]$script:vCPU = (read-host `n "Enter the number of CPUs")
[int]$script:vram = (read-host `n "Enter the amount of RAM in GB")
[int]$script:vmdisk2 = (read-host `n "Enter data disk size in GB")
#need to populate OS ID with proper string to match the label
write-host `n "Select OS Version"
write-host `n "0 - Win2k8R2"
write-host `n "1 - Win2k8x64"
write-host `n "2 - Win2k8x86"
write-host `n "3 - Win2k3x86"
write-host `n "4 - Win2k3x64"
$answer = read-host `n "Enter the number for the OS you're installing"
if($answer -eq "0"){$script:osid = "windows7Server64Guest"}
elseif($answer -eq "1"){$script:osid = "winLonghorn64Guest"}
elseif($answer -eq "2"){$script:osid = "winLonghornGuest"}
elseif($answer -eq "3"){$script:osid = "winNetEnterpriseGuest"}
elseif($answer -eq "4"){$script:osid = "winNetEnterprise64Guest"}
}
#gets the desired cluster
#as well as a host in that cluster to gather network & datastore info from
#then builds on that node of the cluster
#notice no sort order, so it won't pull the same host every time
Function ChooseCluster{
$clslist = Get-cluster |sort name
$i = 0
write-host -foregroundcolor green `n "Choose a cluster"
foreach ($cluster in $clslist){
write-host -foregroundcolor green "$i - $cluster"
$i++
}
$answer = read-host `n "Enter the number for the cluster you want"
$script:clustername = $clslist[$answer]
$vmhosts = get-vmhost -location $script:clustername
$script:vmhostname = $vmhosts[0]
}
#lists datastores for one host of the cluster
#shows provisioned space as well as free space
#yellow if less than 150GB free
#red if less than 100GB free
Function ChooseDatastore{
$datastores = Get-Datastore -vmhost $script:vmhostname |sort FreeSpaceMB -descending
$i = 0
write-host -foregroundcolor green `n "Choose a Datastore"
foreach ($store in $datastores){
$color = "green"
if ($store.FreeSpaceMB -lt 153600){$color = "yellow"}
if ($store.FreeSpaceMB -lt 102400){$color = "red"}
$ds = Get-Datastore $store |sort name | Get-View
$dsout = $ds | Select -ExpandProperty Summary | Select Name, @{N="Capacity GB"; E={[math]::round($_.Capacity/1073741824, 2)}}, @{N="Free GB"; E={[math]::round($_.FreeSpace/1073741824, 2)}}, @{N="Provisioned GB"; E={[math]::round(($_.Capacity - $_.FreeSpace + $_.Uncommitted)/1073741824, 2)}} |sort name
write-host -foregroundcolor $color "$i - $dsout"
$i++
}
$answer = read-host `n "Enter the number for the datastore you want"
$script:store = $datastores[$answer]
}
#pulls available networks from the host in the cluster
Function ChooseNetwork{
$networklist = Get-VirtualPortGroup -vmhost $script:vmhostname |sort name
$i = 0
write-host -foregroundcolor green `n "Choose a network"
foreach ($network in $networklist){
write-host -foregroundcolor green "$i - $network"
$i++
}
$answer = read-host `n "Enter the number for the network you want"
$script:networklabel = $networklist[$answer]
}
#connects to vcenter
function ConnectVCenter($script:vcenter){
connect-viserver $script:vcenter > $NULL 2>&1
}
#change -DiskMB to change disk 0:0 to the desired size
function CreateVM{
#this creates the VM itself
new-vm -vmhost $script:vmhostname -name $script:vmname -Datastore $script:store -DiskMB 65536 -diskstorageformat Thin -MemoryMB ($script:vRAM * 1024) -NumCpu $script:vcpu -CD -GuestID $script:osid -NetworkName $script:networklabel -Description $script:desc
#this adds the data disk, since accepted size is kb, and prompt was gb, we have to convert it
get-vm $script:vmname | New-HardDisk -capacitykb ($script:vmdisk2 * 1048576) -StorageFormat Thin
}
#disconnect from vc, null out variables just in case
function garbagecollection{
$script:clustername = $null
$script:vmhostname = $null
$script:networklabel = $null
$script:vcenter = $null
$script:vmname = $null
$script:vCPU = $null
$script:vRAM = $null
$script:vmdisk2 = $null
$script:store = $null
$script:desc = $null
$script:osid = $null
disconnect-viserver -confirm:$false
}
function AddToSCCM{
#sccm variables here
$SCCMServer = "" #enter the SCCM server name, used for WMI
$SCCMSite = "Site_" #example: Site_WSS, always 'Site_' and then 3 letter site code
$Colon = ":" #don't change this, makes life easier for the wmi path
#we need the mac to import computer into SCCM
$vnic = Get-NetworkAdapter (get-vm $script:vmname)
$mac = $vnic.MacAddress
#specify collection based on OS ID
if($script:osid -eq "winLonghornGuest"){$targetColl = "2008 x86 Mandatory"}
elseif($script:osid -eq "winLonghorn64Guest"){$targetColl = "2008 x64 Mandatory"}
elseif($script:osid -eq "windows7Server64Guest"){$targetColl = "2008 R2 Mandatory"}
elseif($script:osid -eq "winNetEnterpriseGuest"){$targetColl = "2003 x86 Mandatory"}
elseif($script:osid -eq "winNetEnterprise64Guest"){$targetColl = "2003 x64 Mandatory"}
#create computer object
$Method = "ImportMachineEntry"
$Class = "SMS_Site"
$MC = [WmiClass]"\\$SCCMServer\ROOT\SMS\$SCCMSite$Colon$Class"
$InParams = $mc.psbase.GetMethodParameters($Method)
$InParams.MACAddress = $mac
$InParams.NetbiosName = $script:vmname
$InParams.OverwriteExistingRecord = $false
$inparams.PSBase.properties | select name,Value
$objCMComputer = $mc.PSBase.InvokeMethod($Method, $inParams, $Null)
#create direct rule for collection for target collection
$Class = "SMS_CollectionRuleDirect"
$objColRuledirect = [WmiClass]"\\$SCCMServer\ROOT\SMS\$SCCMSite$Colon$Class"
$objColRuleDirect.psbase.properties["ResourceClassName"].value = "SMS_R_System"
$objColRuleDirect.psbase.properties["ResourceID"].value = $objCMComputer.resourceID
$Collection = gwmi -computer $SCCMServer -namespace "root\sms\$SCCMSite" -class "SMS_Collection"
$svrCollection = $collection | where{$_.Name -eq "$targetColl"}
#add computer to target collection
$Class = "SMS_Collection"
$Method = "AddMembershipRule"
$CollectionID = $svrCollection.CollectionID
$filter="CollectionID = '$CollectionID'"
$MC = Get-WmiObject "SMS_Collection" -computer $SCCMServer -Namespace "ROOT\SMS\$SCCMSite" -filter $filter
$InParams = $mc.psbase.GetMethodParameters($Method)
$InParams.collectionRule = $objColRuledirect
$inparams.PSBase.properties | select name,Value
$AddComp = $mc.PSBase.InvokeMethod($Method, $inParams, $Null)
#update collection membership
start-sleep -s 15 #sleep for 15 seconds before requesting refresh of collection
$Method = "RequestRefresh"
$InParams = $mc.psbase.GetMethodParameters($Method)
$InParams.includesubcollections = $false
$inparams.PSBase.properties | select name,Value
$Refresh = $mc.PSBase.InvokeMethod($Method, $inParams, $Null)
}
function LaunchConsole{
$conuser = "conuser"
$conpw = "conpw"
$vm = get-vm $script:vmname
$currentvmhost = (get-vmhost -vm $vm).name
$vmxpath = $vm.ExtensionData.Summary.config.vmpathname
D:\"Program Files (x86)"\VMware\Infrastructure\"Virtual Infrastructure Client"\4.0\vmware-vmrc.exe -u $conuser -p $conpw -h $currentvmhost `"$vmxpath`"
}
##
#
# and now lets run all the functions
#
##
getspecs
ConnectVCenter($script:vcenter)
ChooseCluster
ChooseNetwork
ChooseDatastore
listspecs
CreateVM
start-sleep -s 15
AddToSCCM
start-sleep -s 15
start-vm $script:vmname > $NULL 2>&1
LaunchConsole
garbagecollection
Thanks for posting this- much appreciated. We’re currently trying to redo the way we deploy VMs and this will be very helpful. Thumbs up!
This script has been very helpful to me, many thanks for sharing it.
Wonderful post, found exactly what I needed. Does this script work with ConfigMgr 2012?
I’m not sure, I haven’t tested it against 2012. I have a feeling it won’t, since Microsoft basically did a ground-up rewrite of Config Manager. I might be able to look through WMI on a ConfigMgr machine to figure it out and update if needed, I just don’t have access to one anymore :(
Hi Luke,
Fantastic script…this would be really handy if you could re-write it for ConfigMgr 2012? :)
I’d like to do that. My role changed and I don’t do much with SCCM anyone. I’m hoping to fix that, soon, though. Maybe I’ll get a chance to do it some day. :-)
Thanks for the script. It was a great starting point, and made an early proof of concept so that i knew what I was trying to do would be possible. Much of it had to be rewrote for newer vmware and sccm, the functions are still similar.
For anyone else that makes it as far as my comment, you could also call for variables to throw into your OSD task sequence