VMware Cloud Community
aplechaty
Enthusiast
Enthusiast
Jump to solution

Adding a Tag to A VM?

I have a script currently for deploying virtual machines. What I am looking to do is prompt the user with a list of Tags to select from as follows.

$Tags = "DEV-2-Week-Linux","DEV-4-Week-Linux","PROD-2-Week-Linux","PROD-2-Week-Windows"

So as the script runs I want the user to be prompted to select one of the tags. They make their selection and the script continues on. I then need the script at some point to assign the selected tag to the VM as it is created. 

 

I am having a hard time figuring out how to actually set the tag on the newly created VM. Any help is greatly appreciated. Thanks in advance.

0 Kudos
1 Solution

Accepted Solutions
LucD
Leadership
Leadership
Jump to solution

You are not storing the object returned by New-VM in a variable, and, yes, you have to use the variable where you define the tags instead of $tag.

 $vm = New-VM -Name $ChosenName -Template $ChosenTemplate -OSCustomizationSpec $ChosenCustomization -Datastore $ChosenDatastore -Location $ChosenFolder -NetworkName $ChosenNetwork -VMHost $ChosenHost -ResourcePool $ChosenCluster

New-TagAssignment -Entity $vm -Tag  $BackupTag


Blog: lucd.info  Twitter: @LucD22  Co-author PowerCLI Reference

View solution in original post

30 Replies
LucD
Leadership
Leadership
Jump to solution

You can use the New-TagAssignment cmdlet for that.


Blog: lucd.info  Twitter: @LucD22  Co-author PowerCLI Reference

0 Kudos
aplechaty
Enthusiast
Enthusiast
Jump to solution

Thanks, I am looking for the exact string that would assign the tag selected. I'm not quite sure how to format the command using a pulled in variable? Also this script creates the Vm it doesn't already exist so how do I add an entity that is yet to be created?

 

0 Kudos
aplechaty
Enthusiast
Enthusiast
Jump to solution

Here is my script below, as you can see I added the Backup tag variable now I just need the proper command to assign the selected tag to the VM. 

On a separate note, I am also getting an error on line 130 which I have Italics below.

 
#Variables
    $VCenterServer = "myvcenter.domain.net"
    $Environments = "PROD","DEV"
    $BusinessDivisions = "Corporate","DevOps","EA","ECM","EDI","Network Services","RCO","RCS"
    $ServerFunctions = "Application","Web","Database","File","Management"
    $DMZDomain = "domain.dmz"
    $InternalDomain = "domain.net"
    $DMZDNS = Resolve-DnsName -Type NS -Name $DMZDomain
    $InternalDNS = Resolve-DnsName -Type NS -Name $InternalDomain    
    $IPPattern = "^([1-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])(\.([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])){3}$"
    $CurrentDate = Get-Date -Format d
    $BackupTag = "DomainControllers","DEV-2-Week-Linux","DEV-2-Week-Windows","DEV-4-Week-Linux","DEV-4-Week-Windows","PROD-2-Week-Linux","PROD-2-Week-Windows",'PROD-4-Week-Linux","PROD-4-Week-Windows"
   

#Functions
    #Quick function to give the user a prompt of specific options.
        function Get-UserPrompt {
            param (
                [Parameter(Mandatory=$true)]
                [string[]]$Options,
                [Parameter(Mandatory=$true)]
                [string]$Prompt        
            )
           
            [int]$Response = 0;
            [bool]$ValidResponse = $false    

            while (!($ValidResponse)) {            
                [int]$OptionNo = 0

                Write-Host $Prompt -ForegroundColor DarkYellow
                Write-Host "[0]: Cancel"

                foreach ($Option in $Options) {
                    $OptionNo += 1
                    Write-Host ("[$OptionNo]: {0}" -f $Option)
                }

                if ([Int]::TryParse((Read-Host), [ref]$Response)) {
                    if ($Response -eq 0) {
                        return ''
                    }
                    elseif($Response -le $OptionNo) {
                        $ValidResponse = $true
                    }
                }
            }

            return $Options.Get($Response - 1)
        }
   
    #Quick function to request specified information.
        Function Get-DeploymentVariables{
            param(
                [Parameter(Mandatory=$true)]
                [string]$Prompt
                )
            Write-Host $Prompt -ForegroundColor DarkYellow
            Read-Host
        }
   
    #Pull correct folder by specifying the path. Copied directly from: https://www.lucd.info/2012/05/18/folder-by-path/
        function Get-FolderByPath{
            <#
            .SYNOPSIS Retrieve folders by giving a path
            .DESCRIPTION The function will retrieve a folder by it's path.
            The path can contain any type of leave (folder or datacenter).
            .NOTES
            Author: Luc Dekens .PARAMETER Path The path to the folder. This is a required parameter.
            .PARAMETER
            Path The path to the folder. This is a required parameter.
            .PARAMETER
            Separator The character that is used to separate the leaves in the path. The default is '/'
            .EXAMPLE
            PS> Get-FolderByPath -Path "Folder1/Datacenter/Folder2"
            .EXAMPLE
            PS> Get-FolderByPath -Path "Folder1>Folder2" -Separator '>'
            #>
           
            param(
            [CmdletBinding()]
            [parameter(Mandatory = $true)]
            [System.String[]]${Path},
            [char]${Separator} = '/'
            )
           
            process{
                if((Get-PowerCLIConfiguration).DefaultVIServerMode -eq "Multiple"){
                $vcs = $global:defaultVIServers
                }
                else{
                $vcs = $global:defaultVIServers[0]
                }
                $folders = @()
           
                foreach($vc in $vcs){
                $si = Get-View ServiceInstance -Server $vc
                $rootName = (Get-View -Id $si.Content.RootFolder -Property Name).Name
                foreach($strPath in $Path){
                    $root = Get-Folder -Name $rootName -Server $vc -ErrorAction SilentlyContinue
                    $strPath.Split($Separator) | ForEach-Object{
                    $root = Get-Inventory -Name $_ -Location $root -NoRecursion -Server $vc -ErrorAction SilentlyContinue
                    if((Get-Inventory -Location $root -NoRecursion | Select-Object -ExpandProperty Name) -contains "vm"){
                        $root = Get-Inventory -Name "vm" -Location $root -Server $vc -NoRecursion
                    }
                    }
                    $root | Where-Object {$_ -is [VMware.VimAutomation.ViCore.Impl.V1.Inventory.FolderImpl]}|ForEach-Object{
                    $folders += Get-Folder -Name $_.Name -Location $root.Parent -NoRecursion -Server $vc
                    }
                }
                }
                $folders
            }
            }

#Connect to VCenter Server. Will prompt for credentials.
    Connect-VIServer $VCenterServer

#Prompts for all variables.
    #PROD/DEV/QA/TEST.
        $ChosenEnvironment = Get-UserPrompt -Options $Environments -Prompt "Choose Environment."
        if($ChosenEnvironment -eq "PROD"){
            $ChosenHost = Get-VMHost -Location "Expedient Production" | Sort-Object MemoryUsageGB -Descending | Select-Object -Last 1
            $FolderPathStart = "Expedient Production/"
            $ChosenCluster = Get-Cluster -Name "Expedient Production"
        }
        if($ChosenEnvironment -eq "DEV"){
            $ChosenHost = Get-VMHost -Location "Expedient Development" | Sort-Object MemoryUsageGB -Descending | Select-Object -Last 1
            $FolderPathStart = "Expedient Development/"
            $ChosenCluster = "Expedient Development"
            $ChosenCluster = Get-Cluster -Name "Expedient Development"
        }

    #Business Division
        $ChosenDivision = Get-UserPrompt -Options $BusinessDivisions -Prompt "Choose Business Division."
   
    #VM Notes
        $ChosenNotes = Get-DeploymentVariables -Prompt "Enter VM Notes"

    #Server Owner
        $ChosenOwner = Get-DeploymentVariables -Prompt "Enter Server Owner"

    #Server Function
        $ChosenFunction = Get-UserPrompt -Options $ServerFunctions -Prompt "Choose Server Function"

    #Creator
        $ChosenCreator = Get-DeploymentVariables -Prompt "Enter Your Name"

    #HD Event
        $ChosenHDEvent = Get-DeploymentVariables -Prompt "Enter HD Event Number"
   
    #Domain.
        $ChosenDomain = Get-UserPrompt -Options ("DMZ","Internal") -Prompt "Choose Domain."

    #OS.
        $ChosenOS = Get-UserPrompt -Options ("2019","2022") -Prompt "Choose OS."
        if($ChosenOS -eq "2019"){
            $ChosenTemplate = Get-Template -Name "SRV2019_Template"
        }
        if($ChosenOS -eq "2022"){
            $ChosenTemplate = Get-Template -Name "SRV2022_Template"
        }
    #Name.
        $ChosenName = Get-DeploymentVariables -Prompt "Enter Server Name"

    #Network. This may need to change when we switch to distributed switches.
        $VMNetworks = Get-VirtualPortGroup | Sort-Object Name | Get-Unique
        $ChosenNetwork = Get-UserPrompt -Options $VMNetworks -Prompt "Choose Network."
       
        Do{
            $ChosenIP = Get-DeploymentVariables -Prompt "Enter IP Address."
            $IPTest = $null
            $IPTest = Test-Connection $ChosenIP -ErrorAction Ignore
            $IPCheck = $ChosenIP -match $IPPattern
            if($IPCheck -eq $true){
                if($null -ne $IPTest){
                    Write-Host "IP is already in use. Try again." -ForegroundColor Red
                }}
            if($IPCheck -eq $false) {
                Write-Host "Invalid IP address. Please try again." -ForegroundColor Red
            }
        }
        Until ($null -eq $IPTest -and $IPCheck -eq $true)

        Do{
            $ChosenMask = $null
            $ChosenMask = Get-DeploymentVariables -Prompt "Enter Subnet Mask."
            $MaskCheck = $ChosenMask -match $IPPattern
            If($MaskCheck -eq $false){
                Write-Host "Invalid Subnet Mask. Try again." -ForegroundColor Red
            }
        }
        Until ($MaskCheck -eq $true)
       
        Do{
            $ChosenGateway = $null
            $ChosenGateway = Get-DeploymentVariables -Prompt "Enter Gateway."
            $GatewayCheck = $ChosenGateway -match $IPPattern
            If($GatewayCheck -eq $false){
                Write-Host "Invalid gateway, try again." -ForegroundColor Red
            }
        }
        Until ($GatewayCheck -eq $true)

    #Datastore.
        if($ChosenEnvironment -eq "DEV"){
            $Datastores = Get-DatastoreCluster -Location "Mydomain Development" | Select-Object Name  
            $ChosenDatastore = Get-UserPrompt -Options $Datastores.Name -Prompt "Choose Datastore"
        }
        if($ChosenEnvironment -eq "PROD"){
            $Datastores = Get-DatastoreCluster -Location "Mydomain Production" | Select-Object Name  
            $ChosenDatastore = Get-UserPrompt -Options $Datastores.Name -Prompt "Choose Datastore"
        }
   
    #Socket count.
        $ChosenSockets = Get-UserPrompt -Options ("2","4","6","8","10","12") -Prompt "Choose Number of Cores"

    #Core count.
        #$ChosenCores = Get-UserPrompt -Options ("2","3","4","5","6") -Prompt "Choose Number of Cores Per Socket"
        $ChosenCores = $ChosenSockets/2

    #Memory.
        $ChosenMemory = Get-UserPrompt -Options ("6","8","10","12","14","16") -Prompt "Choose Memory GB"

    #Update group.
        $ADUpdateGroup = Get-ADGroup -Filter {Name -Like "*WSUS*" -and Name -NotLike "WSUSUpdates"} | Sort-Object Name
        $ChosenUpdateGroup = Get-UserPrompt -Options $ADUpdateGroup.Name -Prompt "Choose Update Group"



#Script
    #Confirm chosen options are correct.
        $Title = "Confirmation"
        $Prompt = "Verify the following selections:

        Environment - $ChosenEnvironment
        Business Division - $ChosenDivision
        Owner = $ChosenOwner
        Server Function - $ChosenFunction
        Notes - $ChosenNotes
        Creator - $ChosenCreator
        Helpdesk - $ChosenHDEvent
        Creation Date - $CurrentDate
        Domain - $ChosenDomain
        OS - $ChosenOS
        Name - $ChosenName
        VM Network - $ChosenNetwork
        IP Address - $ChosenIP
        Subnet Mask - $ChosenMask
        Gateway - $ChosenGateway
        Datastore - $ChosenDatastore
        Socket Count - $ChosenSockets
        Core Count Per Socket - $ChosenCores
        Memory - $ChosenMemory
        Update Group - $ChosenUpdateGroup
        `nAre you sure you want to continue?
        `nYou will need to manually undo any changes that happen after this point."
        $Choices = [System.Management.Automation.Host.ChoiceDescription[]] @("Yes", "Cancel")
        $Default = 1
        $Choice = $host.UI.PromptForChoice($Title, $Prompt, $Choices, $Default)
        switch($Choice)
            {
                0 {Write-Host "Continuing.
                Please Wait your Virtual Machine build is in progress! Once the cursosr has returned you can close this Powershell window and proceed to vCenter for any additional configuration!
                " -ForegroundColor Green}
                1 {Write-Host "Cancelling." -ForegroundColor Red
                    Return}
            }
   
    #Deploy VM. Must program in wait for spin-up.
        #Select OS Customization Spec
            if($ChosenDomain -eq "DMZ"){
                $OSCustomization = Get-OSCustomizationSpec -Name "Server_2019/2022_Template_DMZ"
                $ChosenDNS = $DMZDNS
            }
            if($ChosenDomain -eq "Internal"){
                $OSCustomization = Get-OSCustomizationSpec -Name "Server_2019/2022_Template_NET"
                $ChosenDNS = $InternalDNS
            }
            Get-OSCustomizationSpec -Name Temp | Remove-OSCustomizationSpec -confirm:$false -ErrorAction Ignore | Out-Null
            Get-OSCustomizationSpec -Name $OSCustomization | New-OSCustomizationSpec -Name Temp -Type NonPersistent | Set-OSCustomizationSpec -NamingScheme vm | Out-Null
            Get-OSCustomizationSpec -Name Temp | Get-OSCustomizationNicMapping | Set-OSCustomizationNicMapping -IpMode UseStaticIP -IpAddress $ChosenIP -SubnetMask $ChosenMask -DefaultGateway $ChosenGateway -Dns $ChosenDNS.IP4Address | Out-Null
            $ChosenCustomization = Get-OSCustomizationSpec -Name Temp
       
        #Select VM Cluster  

       
        #Deploy VM
            $FolderName = $FolderPathStart+"/"+$ChosenDivision
            $ChosenFolder = Get-FolderByPath -Path  $FolderName
            New-VM -Name $ChosenName -Template $ChosenTemplate -OSCustomizationSpec $ChosenCustomization -Datastore $ChosenDatastore -Location $ChosenFolder -NetworkName $ChosenNetwork -VMHost $ChosenHost -ResourcePool $ChosenCluster | Out-Null
            Set-VM -VM $ChosenName -NumCpu $ChosenSockets -CoresPerSocket $ChosenCores -MemoryGB $ChosenMemory -Notes $ChosenNotes -Confirm:$false | Out-Null
            Set-Annotation -Entity $ChosenName -CustomAttribute "Environment" -Value $ChosenEnvironment | Out-Null
            Set-Annotation -Entity $ChosenName -CustomAttribute "Business Division" -Value $ChosenDivision| Out-Null
            Set-Annotation -Entity $ChosenName -CustomAttribute "Created Date" -Value $CurrentDate | Out-Null
            Set-Annotation -Entity $ChosenName -CustomAttribute "Creator" -Value $ChosenCreator | Out-Null
            Set-Annotation -Entity $ChosenName -CustomAttribute "Domain" -Value $ChosenDomain | Out-Null
            Set-Annotation -Entity $ChosenName -CustomAttribute "Owner" -Value $ChosenOwner | Out-Null
            Set-Annotation -Entity $ChosenName -CustomAttribute "Server Function" -Value $ChosenFunction | Out-Null
            Set-Annotation -Entity $ChosenName -CustomAttribute "HD Event" -Value $ChosenHDEvent | Out-Null
            Start-VM -VM $ChosenName | Out-Null
   
    #Ensure VM is ready to go.
        #Options:
            #Get-ADComputer returns a non-error. Requires unique name, which can be checked for and possibly deleted at beginning of script.
            #Time delay.
    #Modify Windows settings
    #Update VMTools
    #Update OS
0 Kudos
LucD
Leadership
Leadership
Jump to solution

You can not add a Tag to "... entity that is yet to be created"

Not sure how you coded the creation of the VM, but a New-VM cmdlet returns an object which you can then use on the New-TagAssigment cmdlet as the value for the Entity parameter.


Blog: lucd.info  Twitter: @LucD22  Co-author PowerCLI Reference

0 Kudos
aplechaty
Enthusiast
Enthusiast
Jump to solution

Here is the existing script. I added the Backup type variables just need to know if I can add the tag at some point so we don't have to do so after the fact.

 

#Variables
    $VCenterServer = "myvcenter.mydomain.net"
    $Environments = "PROD","DEV"
    $BusinessDivisions = "Corporate","DevOps","EA","ECM","EDI","Network Services","RCO","RCS"
    $ServerFunctions = "Application","Web","Database","File","Management"
    $DMZDomain = "domain.dmz"
    $InternalDomain = "domain.net"
    $DMZDNS = Resolve-DnsName -Type NS -Name $DMZDomain
    $InternalDNS = Resolve-DnsName -Type NS -Name $InternalDomain    
    $IPPattern = "^([1-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])(\.([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])){3}$"
    $CurrentDate = Get-Date -Format d
    $BackupTag = "DomainControllers","DEV-2-Week-Linux","DEV-2-Week-Windows","DEV-4-Week-Linux","DEV-4-Week-Windows","PROD-2-Week-Linux","PROD-2-Week-Windows",'PROD-4-Week-Linux","PROD-4-Week-Windows"
   

#Functions
    #Quick function to give the user a prompt of specific options.
        function Get-UserPrompt {
            param (
                [Parameter(Mandatory=$true)]
                [string[]]$Options,
                [Parameter(Mandatory=$true)]
                [string]$Prompt        
            )
           
            [int]$Response = 0;
            [bool]$ValidResponse = $false    

            while (!($ValidResponse)) {            
                [int]$OptionNo = 0

                Write-Host $Prompt -ForegroundColor DarkYellow
                Write-Host "[0]: Cancel"

                foreach ($Option in $Options) {
                    $OptionNo += 1
                    Write-Host ("[$OptionNo]: {0}" -f $Option)
                }

                if ([Int]::TryParse((Read-Host), [ref]$Response)) {
                    if ($Response -eq 0) {
                        return ''
                    }
                    elseif($Response -le $OptionNo) {
                        $ValidResponse = $true
                    }
                }
            }

            return $Options.Get($Response - 1)
        }
   
    #Quick function to request specified information.
        Function Get-DeploymentVariables{
            param(
                [Parameter(Mandatory=$true)]
                [string]$Prompt
                )
            Write-Host $Prompt -ForegroundColor DarkYellow
            Read-Host
        }
   
    #Pull correct folder by specifying the path. Copied directly from: https://www.lucd.info/2012/05/18/folder-by-path/
        function Get-FolderByPath{
            <#
            .SYNOPSIS Retrieve folders by giving a path
            .DESCRIPTION The function will retrieve a folder by it's path.
            The path can contain any type of leave (folder or datacenter).
            .NOTES
            Author: Luc Dekens .PARAMETER Path The path to the folder. This is a required parameter.
            .PARAMETER
            Path The path to the folder. This is a required parameter.
            .PARAMETER
            Separator The character that is used to separate the leaves in the path. The default is '/'
            .EXAMPLE
            PS> Get-FolderByPath -Path "Folder1/Datacenter/Folder2"
            .EXAMPLE
            PS> Get-FolderByPath -Path "Folder1>Folder2" -Separator '>'
            #>
           
            param(
            [CmdletBinding()]
            [parameter(Mandatory = $true)]
            [System.String[]]${Path},
            [char]${Separator} = '/'
            )
           
            process{
                if((Get-PowerCLIConfiguration).DefaultVIServerMode -eq "Multiple"){
                $vcs = $global:defaultVIServers
                }
                else{
                $vcs = $global:defaultVIServers[0]
                }
                $folders = @()
           
                foreach($vc in $vcs){
                $si = Get-View ServiceInstance -Server $vc
                $rootName = (Get-View -Id $si.Content.RootFolder -Property Name).Name
                foreach($strPath in $Path){
                    $root = Get-Folder -Name $rootName -Server $vc -ErrorAction SilentlyContinue
                    $strPath.Split($Separator) | ForEach-Object{
                    $root = Get-Inventory -Name $_ -Location $root -NoRecursion -Server $vc -ErrorAction SilentlyContinue
                    if((Get-Inventory -Location $root -NoRecursion | Select-Object -ExpandProperty Name) -contains "vm"){
                        $root = Get-Inventory -Name "vm" -Location $root -Server $vc -NoRecursion
                    }
                    }
                    $root | Where-Object {$_ -is [VMware.VimAutomation.ViCore.Impl.V1.Inventory.FolderImpl]}|ForEach-Object{
                    $folders += Get-Folder -Name $_.Name -Location $root.Parent -NoRecursion -Server $vc
                    }
                }
                }
                $folders
            }
            }

#Connect to VCenter Server. Will prompt for credentials.
    Connect-VIServer $VCenterServer

#Prompts for all variables.
    #PROD/DEV/QA/TEST.
        $ChosenEnvironment = Get-UserPrompt -Options $Environments -Prompt "Choose Environment."
        if($ChosenEnvironment -eq "PROD"){
            $ChosenHost = Get-VMHost -Location "mydomain Production" | Sort-Object MemoryUsageGB -Descending | Select-Object -Last 1
            $FolderPathStart = "mydomain Production/"
            $ChosenCluster = Get-Cluster -Name "mydomain Production"
        }
        if($ChosenEnvironment -eq "DEV"){
            $ChosenHost = Get-VMHost -Location "mydomain Development" | Sort-Object MemoryUsageGB -Descending | Select-Object -Last 1
            $FolderPathStart = "mydomain Development/"
            $ChosenCluster = "mydomain Development"
            $ChosenCluster = Get-Cluster -Name "mydomain Development"
        }

    #Business Division
        $ChosenDivision = Get-UserPrompt -Options $BusinessDivisions -Prompt "Choose Business Division."
   
    #VM Notes
        $ChosenNotes = Get-DeploymentVariables -Prompt "Enter VM Notes"

    #Server Owner
        $ChosenOwner = Get-DeploymentVariables -Prompt "Enter Server Owner"

    #Server Function
        $ChosenFunction = Get-UserPrompt -Options $ServerFunctions -Prompt "Choose Server Function"

    #Creator
        $ChosenCreator = Get-DeploymentVariables -Prompt "Enter Your Name"

    #HD Event
        $ChosenHDEvent = Get-DeploymentVariables -Prompt "Enter HD Event Number"
   
    #Domain.
        $ChosenDomain = Get-UserPrompt -Options ("DMZ","Internal") -Prompt "Choose Domain."

    #OS.
        $ChosenOS = Get-UserPrompt -Options ("2019","2022") -Prompt "Choose OS."
        if($ChosenOS -eq "2019"){
            $ChosenTemplate = Get-Template -Name "SRV2019_Template"
        }
        if($ChosenOS -eq "2022"){
            $ChosenTemplate = Get-Template -Name "SRV2022_Template"
        }
    #Name.
        $ChosenName = Get-DeploymentVariables -Prompt "Enter Server Name"

    #Network. This may need to change when we switch to distributed switches.
        $VMNetworks = Get-VirtualPortGroup | Sort-Object Name | Get-Unique
        $ChosenNetwork = Get-UserPrompt -Options $VMNetworks -Prompt "Choose Network."
       
        Do{
            $ChosenIP = Get-DeploymentVariables -Prompt "Enter IP Address."
            $IPTest = $null
            $IPTest = Test-Connection $ChosenIP -ErrorAction Ignore
            $IPCheck = $ChosenIP -match $IPPattern
            if($IPCheck -eq $true){
                if($null -ne $IPTest){
                    Write-Host "IP is already in use. Try again." -ForegroundColor Red
                }}
            if($IPCheck -eq $false) {
                Write-Host "Invalid IP address. Please try again." -ForegroundColor Red
            }
        }
        Until ($null -eq $IPTest -and $IPCheck -eq $true)

        Do{
            $ChosenMask = $null
            $ChosenMask = Get-DeploymentVariables -Prompt "Enter Subnet Mask."
            $MaskCheck = $ChosenMask -match $IPPattern
            If($MaskCheck -eq $false){
                Write-Host "Invalid Subnet Mask. Try again." -ForegroundColor Red
            }
        }
        Until ($MaskCheck -eq $true)
       
        Do{
            $ChosenGateway = $null
            $ChosenGateway = Get-DeploymentVariables -Prompt "Enter Gateway."
            $GatewayCheck = $ChosenGateway -match $IPPattern
            If($GatewayCheck -eq $false){
                Write-Host "Invalid gateway, try again." -ForegroundColor Red
            }
        }
        Until ($GatewayCheck -eq $true)

    #Datastore.
        if($ChosenEnvironment -eq "DEV"){
            $Datastores = Get-DatastoreCluster -Location "mydomain Development" | Select-Object Name  
            $ChosenDatastore = Get-UserPrompt -Options $Datastores.Name -Prompt "Choose Datastore"
        }
        if($ChosenEnvironment -eq "PROD"){
            $Datastores = Get-DatastoreCluster -Location "mydomain Production" | Select-Object Name  
            $ChosenDatastore = Get-UserPrompt -Options $Datastores.Name -Prompt "Choose Datastore"
        }
   
    #Socket count.
        $ChosenSockets = Get-UserPrompt -Options ("2","4","6","8","10","12") -Prompt "Choose Number of Cores"

    #Core count.
        #$ChosenCores = Get-UserPrompt -Options ("2","3","4","5","6") -Prompt "Choose Number of Cores Per Socket"
        $ChosenCores = $ChosenSockets/2

    #Memory.
        $ChosenMemory = Get-UserPrompt -Options ("6","8","10","12","14","16") -Prompt "Choose Memory GB"

    #Update group.
        $ADUpdateGroup = Get-ADGroup -Filter {Name -Like "*WSUS*" -and Name -NotLike "WSUSUpdates"} | Sort-Object Name
        $ChosenUpdateGroup = Get-UserPrompt -Options $ADUpdateGroup.Name -Prompt "Choose Update Group"



#Script
    #Confirm chosen options are correct.
        $Title = "Confirmation"
        $Prompt = "Verify the following selections:

        Environment - $ChosenEnvironment
        Business Division - $ChosenDivision
        Owner = $ChosenOwner
        Server Function - $ChosenFunction
        Notes - $ChosenNotes
        Creator - $ChosenCreator
        Helpdesk - $ChosenHDEvent
        Creation Date - $CurrentDate
        Domain - $ChosenDomain
        OS - $ChosenOS
        Name - $ChosenName
        VM Network - $ChosenNetwork
        IP Address - $ChosenIP
        Subnet Mask - $ChosenMask
        Gateway - $ChosenGateway
        Datastore - $ChosenDatastore
        Socket Count - $ChosenSockets
        Core Count Per Socket - $ChosenCores
        Memory - $ChosenMemory
        Update Group - $ChosenUpdateGroup
        `nAre you sure you want to continue?
        `nYou will need to manually undo any changes that happen after this point."
        $Choices = [System.Management.Automation.Host.ChoiceDescription[]] @("Yes", "Cancel")
        $Default = 1
        $Choice = $host.UI.PromptForChoice($Title, $Prompt, $Choices, $Default)
        switch($Choice)
            {
                0 {Write-Host "Continuing.
                Please Wait your Virtual Machine build is in progress! Once the cursosr has returned you can close this Powershell window and proceed to vCenter for any additional configuration!
                " -ForegroundColor Green}
                1 {Write-Host "Cancelling." -ForegroundColor Red
                    Return}
            }
   
    #Deploy VM. Must program in wait for spin-up.
        #Select OS Customization Spec
            if($ChosenDomain -eq "DMZ"){
                $OSCustomization = Get-OSCustomizationSpec -Name "Server_2019/2022_Template_DMZ"
                $ChosenDNS = $DMZDNS
            }
            if($ChosenDomain -eq "Internal"){
                $OSCustomization = Get-OSCustomizationSpec -Name "Server_2019/2022_Template_NET"
                $ChosenDNS = $InternalDNS
            }
            Get-OSCustomizationSpec -Name Temp | Remove-OSCustomizationSpec -confirm:$false -ErrorAction Ignore | Out-Null
            Get-OSCustomizationSpec -Name $OSCustomization | New-OSCustomizationSpec -Name Temp -Type NonPersistent | Set-OSCustomizationSpec -NamingScheme vm | Out-Null
            Get-OSCustomizationSpec -Name Temp | Get-OSCustomizationNicMapping | Set-OSCustomizationNicMapping -IpMode UseStaticIP -IpAddress $ChosenIP -SubnetMask $ChosenMask -DefaultGateway $ChosenGateway -Dns $ChosenDNS.IP4Address | Out-Null
            $ChosenCustomization = Get-OSCustomizationSpec -Name Temp
       
        #Select VM Cluster  

       
        #Deploy VM
            $FolderName = $FolderPathStart+"/"+$ChosenDivision
            $ChosenFolder = Get-FolderByPath -Path  $FolderName
            New-VM -Name $ChosenName -Template $ChosenTemplate -OSCustomizationSpec $ChosenCustomization -Datastore $ChosenDatastore -Location $ChosenFolder -NetworkName $ChosenNetwork -VMHost $ChosenHost -ResourcePool $ChosenCluster | Out-Null
            Set-VM -VM $ChosenName -NumCpu $ChosenSockets -CoresPerSocket $ChosenCores -MemoryGB $ChosenMemory -Notes $ChosenNotes -Confirm:$false | Out-Null
            Set-Annotation -Entity $ChosenName -CustomAttribute "Environment" -Value $ChosenEnvironment | Out-Null
            Set-Annotation -Entity $ChosenName -CustomAttribute "Business Division" -Value $ChosenDivision| Out-Null
            Set-Annotation -Entity $ChosenName -CustomAttribute "Created Date" -Value $CurrentDate | Out-Null
            Set-Annotation -Entity $ChosenName -CustomAttribute "Creator" -Value $ChosenCreator | Out-Null
            Set-Annotation -Entity $ChosenName -CustomAttribute "Domain" -Value $ChosenDomain | Out-Null
            Set-Annotation -Entity $ChosenName -CustomAttribute "Owner" -Value $ChosenOwner | Out-Null
            Set-Annotation -Entity $ChosenName -CustomAttribute "Server Function" -Value $ChosenFunction | Out-Null
            Set-Annotation -Entity $ChosenName -CustomAttribute "HD Event" -Value $ChosenHDEvent | Out-Null
            Start-VM -VM $ChosenName | Out-Null
   
    #Ensure VM is ready to go.
        #Options:
            #Get-ADComputer returns a non-error. Requires unique name, which can be checked for and possibly deleted at beginning of script.
            #Time delay.
    #Modify Windows settings
    #Update VMTools
    #Update OS
0 Kudos
aplechaty
Enthusiast
Enthusiast
Jump to solution

I added the script here yesterday but it is gone. I was hoping at the end of the script the tag could be assigned just not sure how to format the command to propagate the selected variable.

0 Kudos
LucD
Leadership
Leadership
Jump to solution

Without seeing your code it is difficult to help you.


Blog: lucd.info  Twitter: @LucD22  Co-author PowerCLI Reference

0 Kudos
aplechaty
Enthusiast
Enthusiast
Jump to solution

I have attached the powershell script. Thanks in advance.

0 Kudos
LucD
Leadership
Leadership
Jump to solution

If you store the object returned by your New-VM into a variable, you can use the New-TagAssignment cmdlet
Not sure what the actual issue is you are having.

$vm = New-VM -Name $ChosenName -Template $ChosenTemplate -OSCustomizationSpec $ChosenCustomization -Datastore $ChosenDatastore -Location $ChosenFolder -NetworkName $ChosenNetwork -VMHost $ChosenHost -ResourcePool $ChosenCluster

New-TagAssignment -Entity $vm -Tag $tag


Blog: lucd.info  Twitter: @LucD22  Co-author PowerCLI Reference

aplechaty
Enthusiast
Enthusiast
Jump to solution

Just to be clear do I remove the  | Out-Null from the command below and then add the New-Tag=Assignment on the next line or do i leave the | Out-Null?

 

New-VM -Name $ChosenName -Template $ChosenTemplate -OSCustomizationSpec $ChosenCustomization -Datastore $ChosenDatastore -Location $ChosenFolder -NetworkName $ChosenNetwork -VMHost $ChosenHost -ResourcePool $ChosenCluster | Out-Null
 
New-TagAssignment -Entity $vm -Tag $BackupTag
0 Kudos
LucD
Leadership
Leadership
Jump to solution

Since the idea is to capture the object returned by New-VM you should drop the Out-Null


Blog: lucd.info  Twitter: @LucD22  Co-author PowerCLI Reference

aplechaty
Enthusiast
Enthusiast
Jump to solution

Ugh I edited the script and added nettagassignment but now it is breaking higher up where it wasn't before. I attached the updated script. Thanks for the help by the way.

 


At C:\Users\myself\PowerShell-Scripts\vCenter Server Deployment\VMDeployment.ps1:67 char:68
+ ... .DESCRIPTION The function will retrieve a folder by it's path.
+ ~
Unexpected token 's' in expression or statement.
At C:\Users\adplechaty\PowerShell-Scripts\vCenter Server Deployment\VMDeployment.ps1:115 char:13
+ }
+ ~
Unexpected token '}' in expression or statement.
+ CategoryInfo : ParserError: (:) [], ParseException
+ FullyQualifiedErrorId : UnexpectedToken

0 Kudos
LucD
Leadership
Leadership
Jump to solution

You have a typo in line 42, that should be

$BackupTag = "DomainControllers","DEV-2-Week-Linux","DEV-2-Week-Windows","DEV-4-Week-Linux","DEV-4-Week-Windows","PROD-2-Week-Linux","PROD-2-Week-Windows","PROD-4-Week-Linux","PROD-4-Week-Windows"


Blog: lucd.info  Twitter: @LucD22  Co-author PowerCLI Reference

aplechaty
Enthusiast
Enthusiast
Jump to solution

Still getting same errors as the previous post.

0 Kudos
LucD
Leadership
Leadership
Jump to solution

I don't.
That you change that single quote to a double quote?


Blog: lucd.info  Twitter: @LucD22  Co-author PowerCLI Reference

0 Kudos
aplechaty
Enthusiast
Enthusiast
Jump to solution

I think I am in the home stretch with LucD's awesome assistance however i added the line you gave me 

New-TagAssignment -Entity $vm -Tag $tag

 

I get the following when I run the script,

New-TagAssignment : Cannot bind argument to parameter 'Entity' because it is null.
At C:\Users\adplechaty\PowerShell-Scripts\vCenter Server Deployment\7-23-2022_Deployment.ps1:331 char:39
+ New-TagAssignment -Entity $vm -Tag $tag
+ ~~~
+ CategoryInfo : InvalidData: (:) [New-TagAssignment], ParameterBindingValidationException
+ FullyQualifiedErrorId : ParameterArgumentValidationErrorNullNotAllowed,VMware.VimAutomation.ViCore.Cmdlets.Comma
nds.Tagging.NewTagAssignment

 

Should I change $tag to my Variable which is $BackupTag or change it to $ChosenBackupTag?

Also do I need to enter something different than $vm?

 

0 Kudos
aplechaty
Enthusiast
Enthusiast
Jump to solution

Spoiler
Spoiler
Oops i also get all of the following as well, I did not in the past.

WARNING: The 'Version' property of VirtualMachine type is deprecated. Use the 'HardwareVersion' property instead.

PowerState : PoweredOff
Version : Unknown
HardwareVersion : vmx-19
Notes :
Guest : Testing:
NumCpu : 2
CoresPerSocket : 2
MemoryMB : 6144
MemoryGB : 6
VMHostId : HostSystem-host-61
VMHost : myesx01.mydomain.net
VApp :
FolderId : Folder-group-v47
Folder : vm
ResourcePoolId : ResourcePool-resgroup-56
ResourcePool : Resources
PersistentId : 5025456a-4ac0-b3c3-79be-8cdb9a78816e
UsedSpaceGB : 100.00173801742494106292724609
ProvisionedSpaceGB : 106.21403405629098415374755859
DatastoreIdList : {Datastore-datastore-125378}
HARestartPriority : ClusterRestartPriority
HAIsolationResponse : AsSpecifiedByCluster
DrsAutomationLevel : AsSpecifiedByCluster VMSwapfilePolicy : Inherit VMResourceConfiguration : CpuShares:Normal/2000 MemShares:Normal/61440 GuestId : windows2019srvNext_64Guest CreateDate : 7/21/2022 2:12:19 PM SEVEnabled : False
BootDelayMillisecond : 0
MigrationEncryption : Opportunistic
MemoryHotAddEnabled : False
MemoryHotAddIncrement :
MemoryHotAddLimit :
CpuHotAddEnabled : False
CpuHotRemoveEnabled : False
Name : Testing
CustomFields : {[Business Division, ], [Created Date, ], [Creator, ], [Domain, ]...}
ExtensionData : VMware.Vim.VirtualMachine
Id : VirtualMachine-vm-139947
Uid : /VIServer=domain\myself@myvcenter.domain.net:443/VirtualMachine=VirtualMachine-vm-139947/

0 Kudos
Macleud
Enthusiast
Enthusiast
Jump to solution

Hi.

Are you writing the result of New-VM to the $VM variable?

 

$vm = New-VM -Name $ChosenName -Template $ChosenTemplate -OSCustomizationSpec $ChosenCustomization -Datastore $ChosenDatastore -Location $ChosenFolder -NetworkName $ChosenNetwork -VMHost $ChosenHost -ResourcePool $ChosenCluster 

 

 

0 Kudos
aplechaty
Enthusiast
Enthusiast
Jump to solution

Macleud I tried adding the $vm = in front of the New-Vm and it did not work. I have the script running error-free now but it still is not assigning the tag. due to my putting a # in front of the New-TagAssignment command since it was not working. if I can just get the Tag to assign now it would be perfect or close enough at least LOL.

0 Kudos