Wednesday, July 24, 2019

How to query number of computers in the collection (multiple collection)



If you have multiple device collection with almost similar name, and is trying to get how many devices are assigned to the collection, use get-cmcollection and also get-cmcollectionmember function in powershell instead of going through it manually in SCCM console


$coll = get-cmcollection -name "*Language Pack for Windows 10 1709*"

$total = 0
foreach ($colname in $coll)
{
    #Write-Output $colname.Name
    if ($colname.Name -match "-install") 
    {
        $membercoll = (get-cmcollectionmember -CollectionName $($colname.Name))
        write-host $colname.Name : $membercoll.count
        $total = $total + 1
    }

$total



OUTPUT
Microsoft Language Pack for Windows 10 1709 Chinese Simplified 20180604 zh-CN-install (device) : 35
Microsoft Language Pack for Windows 10 1709 Chinese Traditional 20180612 zh-TW-install (device) : 4
Microsoft Language Pack for Windows 10 1709 Croatian 20180521 hr-HR-install (device) : 2
Microsoft Language Pack for Windows 10 1709 Czech 20180523 cs-CZ-install (device) : 30
Microsoft Language Pack for Windows 10 1709 Danish 20180517-install (device) : 31
Microsoft Language Pack for Windows 10 1709 Dutch 20180517 nl-NL-install (device) : 86
Microsoft Language Pack for Windows 10 1709 Finish 20180523 fi-FI-install (device) : 1
Microsoft Language Pack for Windows 10 1709 French 20180516 fr-FR-install (device) : 118
Microsoft Language Pack for Windows 10 1709 German (Germany) 1.0 de-DE-install (device) : 1
Microsoft Language Pack for Windows 10 1709 German 1.20180511-install (device) : 510
Microsoft Language Pack for Windows 10 1709 Hungarian 20180521-install (device) : 18
Microsoft Language Pack for Windows 10 1709 Italian 20180808-install (device) : 2
Microsoft Language Pack for Windows 10 1709 Norwegian 20180523 nb-NO-install (device) : 26
Microsoft Language Pack for Windows 10 1709 Polish (Poland) 1.0 en-US-install (device) : 1
Microsoft Language Pack for Windows 10 1709 Polish 20180515-install (device) : 175
Microsoft Language Pack for Windows 10 1709 Russian 20180514 ru-RU-install (device) : 193
Microsoft Language Pack for Windows 10 1709 Spanish 20180516 es-ES-install (device) : 35
Microsoft Language Pack for Windows 10 1709 Swedish 20190410 sv-SE-install (device) : 9
Microsoft Language Pack for Windows 10 1709 Universal test 20181113 en-US-install (device) : 0
19

Tuesday, November 27, 2018

How to run Modern Desktop Deployment and Management Lab Kit in Hyper-V in Azure environment


How to run Modern Desktop Deployment and Management Lab Kit in Hyper-V in Azure environment

What you need
-        Enterprise MSDN/visualstudio
-        Activate Azure free credits $150 per month in visualstudio portal
-        Login to azure portal

PART 1

Deploy a VM in azure portal

-        Go to azure portal
-        Click on Virtual Machine resource on left hand panel
-        Click Add
-        Subscription choose Visual Studio Enterprise
-        Resource group create new give a name as you like e.g: Ent-VM
-        Virtual machine name Windows-Server
-        Region south east asia
-        Availability options no infrastructure redundancy required
-        Image windows server 2016 datacenter
-        Size search for E4s_v3 then click select
-        Put your username and password remember it
-        Inbound port rules allow selected ports
-        Select inbound ports RDP (3389)
-        Click Next
-        Create and attach new disk you can accept the default value then click OK
-        Click next networking
-        Click next management
-        Auto shutdown On
-        Shutdown time put at the end of your office hour (e.g 17:00:00)
-        Time zone (UTC +8:00) Kuala Lumpur, Singapore
-        Click Review + Create
-        Click Create
-        Wait for the VM deployment to complete
-        Once completed, start the VM, click Connect and download the RDP file. Then connect using your created username and password for the VM



PART 2

Enabling nested virtualization in an Azure VM
-        On the Azure VM, open PowerShell as an Administrator then run this command
Install-WindowsFeature -Name Hyper-V -IncludeManagementTools -Restart
-        Warning - This command restarts the Azure VM. You will lose your RDP connection during the restart process.
-        After the Azure VM restarts, reconnect to your VM using RDP.

Set up internet connectivity for the guest virtual machine
Create a new virtual network adapter for the guest virtual machine and configure a NAT Gateway to enable Internet connectivity.
Create a NAT virtual network switch
1.     On the Azure VM, open PowerShell as an Administrator.
2.     Create an internal switch.
New-VMSwitch -Name "InternalNATSwitch" -SwitchType Internal
3.     View the properties of the switch and note the ifIndex for the new adapter.
Get-NetAdapter
 Note
Take note of the "ifIndex" for the virtual switch you just created.
4.     Create an IP address for the NAT Gateway.
In order to configure the gateway, you need some information about your network:
·        IPAddress - The NAT Gateway IP specifies the IPv4 or IPv6 address to use as the default gateway address for the virtual network subnet. The generic form is a.b.c.1 (for example, "192.168.0.1"). While the final position doesn’t have to be .1, it usually is (based on prefix length). Typically you should use an RFC 1918 private network address space.
·        PrefixLength - The subnet prefix length defines the local subnet size (subnet mask). The subnet prefix length will be an integer value between 0 and 32. 0 would map the entire internet, 32 would only allow one mapped IP. Common values range from 24 to 12 depending on how many IPs need to be attached to the NAT. A common PrefixLength is 24 -- this is a subnet mask of 255.255.255.0.
·        InterfaceIndex - ifIndex is the interface index of the virtual switch created in the previous step.
PowerShellCopy
New-NetIPAddress -IPAddress 192.168.0.1 -PrefixLength 24 -InterfaceIndex 13
Create the NAT network
In order to configure the gateway, you will need to provide information about the network and NAT Gateway:
·        Name - This is the name of the NAT network.
·        InternalIPInterfaceAddressPrefix - The NAT subnet prefix describes both the NAT Gateway IP prefix from above as well as the NAT Subnet Prefix Length from above. The generic form will be a.b.c.0/NAT Subnet Prefix Length.
In PowerShell, create a new NAT network.
PowerShellCopy
New-NetNat -Name "InternalNat" -InternalIPInterfaceAddressPrefix 192.168.0.0/24

Assign an IP address to the guest virtual machine

You can assign an IP address to the guest virtual machine either by manually setting a static IP address on the guest virtual machine or configuring DHCP on the Azure VM to assign the IP address dynamically.

Option 1: Configure DHCP to dynamically assign an IP address to the guest virtual machine

Follow the steps below to configure DHCP on the host virtual machine for dynamic address assignment.

Install DCHP Server on the Azure VM

1.     Open Server Manager. On the Dashboard, click Add roles and features. The Add Roles and Features Wizard appears.
2.     In wizard, click Next until the Server Roles page.
3.     Click to select the DHCP Server checkbox, click Add Features, and then click Next until you complete the wizard.
4.     Click Install.

Configure a new DHCP scope

1.     Open DHCP Manager.
2.     In the navigation pane, expand the server name, right-click IPv4, and click New Scope. The New Scope Wizard appears, click Next.
3.     Enter a Name and Description for the scope and click Next.
4.     Define an IP Range for your DCHP Server (for example, 192.168.0.100 to 192.168.0.200).
5.     Click Next until the Default Gateway page. Enter the IP Address you created earlier (for example, 192.168.0.1) as the Default Gateway.
6.     Click Next until the wizard completes, leaving all default values, then click Finish.














PART 3

Download the Modern Desktop Deployment and Management Lab Kit


Once downloaded, extract the .zip file to your E:\ drive (1TB size). Do not use the temporary D:\ drive as the data will be lost once the VM is reset.
After extracted, open CMD as administrator, go to the extracted folder (e.g: cd E:\MDLAB)
Then run zpaq x SelfService1808.zpaq and wait until completed
Once completed, run the setup as admin. Wait until all VM imported.
*caveat: during the setup, it may prompt that the hyper-v does not have external vSwitch. Create an external vSwitch using Hyper-V manager. Name it as you like as this will not be used later
Open Hyper-V manager, go to HYD-GW1, right click and select settings
Find Intel® 82579LM gigabit Network, change Virtual switch to InternalNATSwitch that was created earlier in PART 2. Then reboot HYD-GW1.



Thursday, November 9, 2017

Replace "space" with"underscore" in folder name - recursively

I have multiple folders with space in the folder name, and need to replace the space with underscore.
Found a simple batch file to do that

From this:


To this:


Script:
@ECHO OFF
SETLOCAL ENABLEDELAYEDEXPANSION

FOR /D %%d IN (*) DO (
   SET "NAME=%%d"
   SET "NEWNAME=!NAME: =_!"
   IF NOT "!NAME!"=="!NEWNAME!" rename "!NAME!" "!NEWNAME!"
)
pause
exit


Wednesday, November 8, 2017

How to read XML using powershell command

PS E:\Win10_SAC_1709\Control> [xml]$XmlDocument = get-content .\DriverGroups.xml
PS E:\Win10_SAC_1709\Control> $XmlDocument

groups
------
groups


PS E:\Win10_SAC_1709\Control> $XmlDocument.group
PS E:\Win10_SAC_1709\Control> $XmlDocument.groups

group
-----
{default, hidden, 213E, 18E5...}


PS E:\Win10_SAC_1709\Control> $XmlDocument.groups.group | ft -a

guid                                   enable Name    Comments
----                                   ------ ----    --------
{00000000-0000-0000-0000-000000000000} True   default default folder (root)
{FFFFFFFF-FFFF-FFFF-FFFF-FFFFFFFFFFFF} True   hidden  This folder contains shared source items that have not been ma...
{40e24ed9-1a13-4da2-a434-0219ad4e7105} True   213E    HP EliteBook Folio 1040 G1
{446b6eec-ae81-4060-9cce-0c525865edf6} False  18E5    HP Elitedesk 800 USDT
{42617501-dbd0-427d-b3dc-a2dc550a631c} False  1992    HP ProBook 645 G1
{cf8166ba-5722-45ff-9b30-aa7e58d7ffa4} False  2129    HP Z840 Workstation
{121569dd-0eb4-4771-9838-bf0cdd465da4} True   WinPE
{11d5ca9b-f2be-45ab-82cf-b0dbb11b938a} True   2270    Folio 1040 G2
{f194946d-bf05-4992-9fe5-ba88314f1330} False  1998    EliteDesk 800 G1 SFF
{c6b8ed4f-6828-485c-822a-0d213c9f71a2} False  18E4    EliteDesk 800 G1 TWR
{48859491-2051-44db-986f-298c27aabca2} False  212A    Z640
{d9e064b6-6ed8-4a0b-a33d-d15127ec0f61} False  805B    705 G2 DM
{719c16f4-d227-4230-a903-193159ecb570} False  805A    705 G2 MT
{8da9ed57-15c2-453b-a31b-8f41459c5501} True   807E    745 G3
{49f21b93-880c-41ba-82ec-9ee7d244dcc8} True   8079    840 G3
{b786bada-aa17-4dbc-8e79-3d926f92383b} False  80D5    Zbook15 G3
{efd6946f-e226-4d91-b342-231fb1918a1f} False  8265    705 G3 MT
{3fc61ad6-0381-46cb-9d01-9db5ecc847e3} True   8266    705 G3 DM
{0b54975f-25ea-4503-8db8-1adae5c368ce} False  2253    ZBook 15 G2
{d062542f-7509-4e66-baa0-5447a5c7f28a} False  1909    ZBook 15 G1
{375766cc-8dd4-43b1-975e-c37b8030d33e} True   8236    Elitebook 745 G4
{637b470a-0622-4953-a54c-c197410731e1} True   828C    EliteBook 840 G4
{d9e41914-8758-4070-ab64-d573931119e4} True   827D    x360 1030 G2
{eab7e4c4-b63b-4b40-b9ec-8070f86b458a} True   828B    X2 612 G2


PS E:\Win10_SAC_1709\Control>

Wednesday, August 20, 2014

Update VMtools and virtual hardware using PowerCLI (UPDATED)

Original content credit to: http://www.getshifting.com/wiki/powerclivmupgrade
================================================================
what this does is:
1) check the VMtool level, if it's not current, upgrade the VMtool.
2) check virtual hardware level, if it is not current, and VMtool is current, upgrade vm hardware
3) else, break

- made some changes to process the vmtool upgrade with runasync switch, and do the poweroff for all VMs at once. this could save some time if you have many VMs in the list

- link to the .ps1 file - CLICK HERE

=========BEGIN CODE============================================

# HOW TO RUN:
# save the list of vm to be updated in text file, and run this script. Enter the filename when requested.
#

$timestamp = Get-Date -format "yyyyMMdd-HH.mm"
$csvfile = ".\$timestamp-vminfo.csv"

Function VM-Selection{
  
      $sourcename = Read-Host "Give the name of the object or inputfile (full path) you want to upgrade"
      if($sourcename){
         $abort = Read-Host "You've chosen $sourcetype with this file: $sourcename, this is your last chance to abort by pressing <CTRL>+C. Press <ENTER> to continue selecting old hardware VMs"
         #$list = Get-Content $sourcename | Foreach-Object {Get-VM $_ | Get-View | Where-Object {-not $_.config.template -and $_.Config.Version -eq "vmx-04" } | Select Name }
         $list = Get-Content $sourcename | Foreach-Object {Get-VM $_ | Get-View | Where-Object {-not $_.config.template} | Select Name }
             $vms = $list
      }
      else{
         Write-Host "$sourcetype file does not exist. Exit the script by pressing <CTRL>+C and try again."
      }
  
   return $vms
}

Function PowerOn-VM($vm){
   Start-VM -VM $vm -Confirm:$false -RunAsync | Out-Null
   Write-Host "$vm is starting!" -ForegroundColor Yellow
   sleep 10

   do {
      $vmview = get-VM $vm | Get-View
        $getvm = Get-VM $vm
        $powerstate = $getvm.PowerState
      $toolsstatus = $vmview.Guest.ToolsStatus

      Write-Host "$vm is starting, powerstate is $powerstate and toolsstatus is $toolsstatus!" -ForegroundColor Yellow
      sleep 5
        #NOTE that if the tools in the VM get the state toolsNotRunning this loop will never end. There needs to be a timekeeper variable to make sure the loop ends

      }until(($powerstate -match "PoweredOn") -and (($toolsstatus -match "toolsOld") -or ($toolsstatus -match "toolsOk") -or ($toolsstatus -match "toolsNotInstalled")))

      if (($toolsstatus -match "toolsOk") -or ($toolsstatus -match "toolsOld")){
       $Startup = "OK"
         Write-Host "$vm is started and has ToolsStatus $toolsstatus"
      }
      else{
       $Startup = "ERROR"
         [console]::ForegroundColor = "Red"
         Read-Host "The ToolsStatus of $vm is $toolsstatus. This is unusual. Press <CTRL>+C to quit the script or press <ENTER> to continue"
         [console]::ResetColor()
      }
    return $Startup
}

Function PowerOff-VM($vm){
   Shutdown-VMGuest -VM $vm -Confirm:$false | Out-Null
   Write-Host "$vm is stopping!" -ForegroundColor Yellow
   sleep 10

   do {
      $vmview = Get-VM $vm | Get-View
      $getvm = Get-VM $vm
        $powerstate = $getvm.PowerState
        $toolsstatus = $vmview.Guest.ToolsStatus

      Write-Host "$vm is stopping with powerstate $powerstate and toolsStatus $toolsstatus!" -ForegroundColor Yellow
      sleep 5

   }until($powerstate -match "PoweredOff")

   if (($powerstate -match "PoweredOff") -and (($toolsstatus -match "toolsNotRunning") -or ($toolsstatus -match "toolsNotInstalled"))){
      $Shutdown = "OK"
        Write-Host "$vm is powered-off"
   }
   else{
      $Shutdown = "ERROR"
        [console]::ForegroundColor = "Red"
        Read-Host "The ToolsStatus of $vm is $toolsstatus. This is unusual. Press <CTRL>+C to quit the script or press <ENTER> to continue"
        [console]::ResetColor()
   }
   return $Shutdown
}

Function Check-ToolsStatus($vm){
   $vmview = get-VM $vm | Get-View
   $status = $vmview.Guest.ToolsStatus

   if ($status -match "toolsOld"){
      $vmTools = "Old"}
   elseif($status -match "toolsNotRunning"){
      $vmTools = "NotRunning"}
   elseif($status -match "toolsNotInstalled"){
      $vmTools = "NotInstalled"}
   elseif($status -match "toolsOK"){
      $vmTools = "OK"}
   else{
      $vmTools = "ERROR"
        Read-Host "The ToolsStatus of $vm is $vmTools. Press <CTRL>+C to quit the script or press <ENTER> to continue"
        }
   return $vmTools
}

Function Check-VMHardwareVersion($vm){
   $vmView = get-VM $vm | Get-View
   $vmVersion = $vmView.Config.Version
   $v9 = "vmx-09"
   $v10 = "vmx-10"

   if (($vmVersion -ne $v9) -or ($vmVersion -ne $v10)){
      $vmHardware = "Old"}
   elseif(($vmVersion -eq $v9) -or ($vmVersion -eq $v10)){
      $vmHardware = "OK"}
   else{
      $vmHardware = "ERROR"
        [console]::ForegroundColor = "Red"
        Read-Host "The Hardware version of $vm is not set to $v4 or $v9. This is unusual. Press <CTRL>+C to quit the script or press <ENTER> to continue"
        [console]::ResetColor()
   }
   return $vmHardware
}

Function Upgrade-VMHardware($vm){
   $vmview = Get-VM $vm | Get-View
   $vmVersion = $vmView.Config.Version
   $v9 = "vmx-09"

   if ($vmVersion -ne $v9){
      Write-Host "Old Version detected" -ForegroundColor Red

# Update Hardware
      Write-Host "Upgrading Hardware on" $vm -ForegroundColor Yellow
      Get-View ($vmView.UpgradeVM_Task($v9)) | Out-Null
   }
}

Function CheckAndUpgradeTools($vm){

   $vmview = Get-VM $VM | Get-View
   $family = $vmview.Guest.GuestFamily
   $vmToolsStatus = Check-ToolsStatus $vm

   if($vmToolsStatus -eq "OK"){
      Write-Host "The VM tools are $vmToolsStatus on $vm"}
   elseif(($family -eq "windowsGuest") -and ($vmToolsStatus -ne "NotInstalled")){
      Write-Host "The VM tools are $vmToolsStatus on $vm. Starting update/install now! This will take at few minutes." -ForegroundColor Red
        Get-Date

      Get-VMGuest $vm | Update-Tools -NoReboot -RunAsync
      ###############changes###########################
#       do{
#       sleep 10
#       Write-Host "Checking ToolsStatus $vm now"
#       $vmToolsStatus = Check-ToolsStatus $vm
#       }until($vmToolsStatus -eq "OK")
#       sleep 60
#     PowerOff-VM $vm
#       PowerOn-VM $vm
        #############end changes#######################
   }
   else{
        # We're skipping all non-windows guest since automated installs are not supported
        Write-Host "$vm is a $family with tools status $vmToolsStatus. Therefore we're skipping this VM" -ForegroundColor Red
   }
}

Function CheckAndUpgrade($vm){

   $vmHardware = Check-VMHardwareVersion $vm
   $vmToolsStatus = Check-ToolsStatus $vm

   if($vmHardware -eq "OK"){
      Write-Host "The hardware level is $vmHardware on $vm"}
   elseif($vmToolsStatus -eq "OK"){
      Write-Host "The hardware level is $vmHardware on $vm." -ForegroundColor Red
      $PowerOffVM = PowerOff-VM $vm
        if($PowerOffVM -eq "OK"){
           Write-Host "Starting upgrade hardware level on $vm."
             Upgrade-VMHardware $vm
           sleep 5
             PowerOn-VM $vm
           Write-Host $vm "is up to date" -ForegroundColor Green
        }
        else{
        Write-Host "There is something wrong with the hardware level or the tools of $vm. Skipping $vm."
        }
   }  
}

Function CreateHWList($vms, $csvfile){
# The setup for this hwlist comes from http://www.warmetal.nl/powerclicsvvminfo
   Write-Host "Creating a CSV File with VM info" -ForegroundColor Yellow

   $MyCol = @()
      ForEach ($item in $vms){
         $vm = $item.Name
             # Variable getvm is required, for some reason the $vm cannot be used to query the host and the IP-address
             $getvm = Get-VM $vm
             $vmview = Get-VM $vm | Get-View

             # VM has to be turned on to make sure all information can be recorded
             $powerstate = $getvm.PowerState
             if ($powerstate -ne "PoweredOn"){
                PowerOn-VM $vm}

             $vmnic = Get-NetworkAdapter -VM $vm
         $nicmac = Get-NetworkAdapter -VM $vm | ForEach-Object {$_.MacAddress}
         $nictype = Get-NetworkAdapter -VM $vm | ForEach-Object {$_.Type}
         $nicname = Get-NetworkAdapter -VM $vm | ForEach-Object {$_.NetworkName}

         $VMInfo = "" | Select VMName,NICCount,IPAddress,MacAddress,NICType,NetworkName,GuestRunningOS,PowerState,ToolsVersion,ToolsStatus,ToolsRunningStatus,HWLevel,VMHost
         $VMInfo.VMName = $vmview.Name
         $VMInfo.NICCount = $vmview.Guest.Net.Count
         $VMInfo.IPAddress = [String]$getvm.Guest.IPAddress
         $VMInfo.MacAddress = [String]$nicmac
         $VMInfo.NICType = [String]$nictype
         $VMInfo.NetworkName = [String]$nicname
         $VMInfo.GuestRunningOS = $vmview.Guest.GuestFullname
         $VMInfo.PowerState = $getvm.PowerState
         $VMInfo.ToolsVersion = $vmview.Guest.ToolsVersion
         $VMInfo.ToolsStatus = $vmview.Guest.ToolsStatus
         $VMInfo.ToolsRunningStatus = $vmview.Guest.ToolsRunningStatus
         $VMInfo.HWLevel = $vmview.Config.Version
         $VMInfo.VMHost = $getvm.VMHost

         $myCol += $VMInfo
        }

   if ((Test-Path -path $csvfile) -ne $True){
      $myCol |Export-csv -NoTypeInformation $csvfile
   }
   else{
      $myCol |Export-csv -NoTypeInformation $csvfile-after.csv
   }
}

function PowerOffAll-VM($vm){
      shutdown-vmguest -VM $vm -Confirm:$false | out-null
}

function PowerOff-vm-check($vm){

            $vmview = get-vm $vm | get-view
            $getvm = get-vm $vm
            $powerstate = $getvm.PowerState
            $toolsstatus = $vmview.Guest.ToolsStatus
           
            #write-host "$vm is stopping with powerstate $powerstate and toolsStatus $toolsstatus!" -foregroundcolor yellow
            if (($powerstate -match "PoweredOff") -and (($toolsstatus -match "toolsNotRunning") -or ($toolsstatus -match "toolsNotInstalled"))){
                        $Shutdown = "OK"
            #     Write-Host "$vm is powered-off"
            }
            else{
                        $Shutdown = "ERROR"
                  [console]::ForegroundColor = "Red"
                  Read-Host "The ToolsStatus of $vm is $toolsstatus. This is unusual. Press <CTRL>+C to quit the script or press <ENTER> to continue"
                  [console]::ResetColor()
            }
           
            return $shutdown
           
}


##################################
# main function
##################################
$vms = VM-Selection

#CreateHWList $vms $csvfile
$vmupgraded = "NO"
foreach($item in $vms){
   $vm = $item.Name
   Write-Host "Working on $vm"
   CheckAndUpgradeTools $vm
}

do{
            sleep 20
            $count = 0
            foreach($vmname in $vms){
                  $vm = $vmname.Name
                  #write-host "checking status for $vm"
                  $vmToolsStatus = Check-ToolsStatus $vm
                  if($vmToolsStatus -ne "OK"){
                        $count += 1
                        $vmupgraded = "yes"
                  }
            }
            write-host "$count VM still in progress"
      }until($count -eq 0)
      write-host "All VM has vmtools upgraded"

write-host "VMtool upgraded status = $vmupgraded"    
Read-Host "Continue to virtual hardware upgrade. Press <CTRL>+C to quit the script or press <ENTER> to continue"

     

if($vmupgraded -eq "yes"){
      foreach($vmname in $vms){
            $vm = $vmname.Name
            PowerOffAll-VM $vm
      }

      do{
            sleep 10
            $count = 0
            write-host "checking power state for all VMs"
            foreach($vmname in $vms){
                  $vm = $vmname.Name
                  $powerState = PowerOff-vm-check $vm
                  if($powerState -ne "OK"){
                        $count += 1
                  }
            }
            write-host "$count VM still powering off" -foregroundcolor yellow
      }until($count -eq 0)
      write-host "All VMs powered off"

      foreach($vmname in $vms){
            $vm = $vmname.Name
            PowerOn-VM $vm
      }
}
     
foreach($item in $vms){
      $vm = $item.Name
      Write-Host "Working on $vm"
      CheckAndUpgrade $vm
}
#CreateHWList $vms $csvfile
###################################
# end main
###################################