zorvek (Kevin Jones)
asked on
Using PowerShell Script from Batch to Control Hyper-V Machine
My source: https://community.spiceworks.com/scripts/show/1898-hyper-v-virtual-machine-backup
My .bat file:
%SystemRoot%\system32\Wind owsPowerSh ell\v1.0\p owershell. exe -Executionpolicy Bypass -command '"C:\Users\My Name\Documents\Scripts\Scr ipts - Other\Start Stop VMs.ps1 C:\Users\My Name\Desktop\hosts.txt 1"'
My .ps1 file:
$waitstart = 200
$waitshutdown = 120
if ($args[1] -match "0") {
$inputfile=get-content $args[0]
foreach ($guest in $inputfile) {
write-host "Starting $guest"
$vm = gwmi -namespace root\virtualization -query "select * from msvm_computersystem where elementname='$guest'"
$result = $vm.requeststatechange(2)
if ($result.returnvalue -match "0") {
start-sleep -s $waitstart
write-host ""
write-host "$guest is started" -foregroundcolor green
write-host ""
}
else {
write-host ""
write-host "unable to start $guest" -foregroundcolor red
write-host ""
}}}
if ($args[1] -match "1") {
$inputfile=get-content $args[0]
foreach ($guest in $inputfile) {
write-host "shutting down $guest"
$vm = gwmi -namespace root\virtualization -query "select * from msvm_computersystem where elementname='$guest'"
$vmname = $vm.name
$vmshut = gwmi -namespace root\virtualization -query "SELECT * FROM Msvm_ShutdownComponent WHERE SystemName='$vmname'"
$result = $vmshut.InitiateShutdown(" $true","no comment")
if ($result.returnvalue -match "0") {
start-sleep -s $waitshutdown
write-host ""
write-host "no error while shutting down $guest"
write-host "shutdown of $guest completed" -foregroundcolor green
write-host ""}
else {
write-host ""
write-host "unable to shutdown $guest" -foregroundcolor red
write-host ""
}}}
else {
write-host "USAGE: to shutdown VMs," -nonewline; write-host ".\managehyperV.ps1 c:\hosts.txt 1" -foregroundcolor yellow
write-host "USAGE: to start VMs," -nonewline; write-host ".\managehyperV.ps1 c:\hosts.txt 0" -foregroundcolor yellow
}
My hosts.txt:
Windows 10 64 Bit
I run the .bat script and nothing happens. No errors. No warnings. No logging. And the VM keeps chugging along.
Kevin
My .bat file:
%SystemRoot%\system32\Wind
My .ps1 file:
$waitstart = 200
$waitshutdown = 120
if ($args[1] -match "0") {
$inputfile=get-content $args[0]
foreach ($guest in $inputfile) {
write-host "Starting $guest"
$vm = gwmi -namespace root\virtualization -query "select * from msvm_computersystem where elementname='$guest'"
$result = $vm.requeststatechange(2)
if ($result.returnvalue -match "0") {
start-sleep -s $waitstart
write-host ""
write-host "$guest is started" -foregroundcolor green
write-host ""
}
else {
write-host ""
write-host "unable to start $guest" -foregroundcolor red
write-host ""
}}}
if ($args[1] -match "1") {
$inputfile=get-content $args[0]
foreach ($guest in $inputfile) {
write-host "shutting down $guest"
$vm = gwmi -namespace root\virtualization -query "select * from msvm_computersystem where elementname='$guest'"
$vmname = $vm.name
$vmshut = gwmi -namespace root\virtualization -query "SELECT * FROM Msvm_ShutdownComponent WHERE SystemName='$vmname'"
$result = $vmshut.InitiateShutdown("
if ($result.returnvalue -match "0") {
start-sleep -s $waitshutdown
write-host ""
write-host "no error while shutting down $guest"
write-host "shutdown of $guest completed" -foregroundcolor green
write-host ""}
else {
write-host ""
write-host "unable to shutdown $guest" -foregroundcolor red
write-host ""
}}}
else {
write-host "USAGE: to shutdown VMs," -nonewline; write-host ".\managehyperV.ps1 c:\hosts.txt 1" -foregroundcolor yellow
write-host "USAGE: to start VMs," -nonewline; write-host ".\managehyperV.ps1 c:\hosts.txt 0" -foregroundcolor yellow
}
My hosts.txt:
Windows 10 64 Bit
I run the .bat script and nothing happens. No errors. No warnings. No logging. And the VM keeps chugging along.
Kevin
Try to replace all occurrances of
root\virtualization
with
root\virtualization\v2
root\virtualization
with
root\virtualization\v2
ASKER
That worked!
Now I'm stuck here:
You cannot call a method on a null-valued expression.
At C:\Users\Kevin Jones\Documents\Scripts\Sc ripts - Other\Start Stop VMs.ps1:32 char:1
+ $result = $vmshut.InitiateShutdown(" $true","no comment")
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~ ~~~~~~~~~~ ~~~~~~~~~~
+ CategoryInfo : InvalidOperation: (:) [], RuntimeException
+ FullyQualifiedErrorId : InvokeMethodOnNull
unable to shutdown Windows 10 64 Bit
The problem is that name is not a property of $vm so $vmshut is nothing.
I'm trying to list the properties of $vm but so far am unable to do so.
Trying this:
Write-Host ($vm | Format-List -Force | Out-String)
but nothing is logged.
Kevin
Now I'm stuck here:
You cannot call a method on a null-valued expression.
At C:\Users\Kevin Jones\Documents\Scripts\Sc
+ $result = $vmshut.InitiateShutdown("
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidOperation: (:) [], RuntimeException
+ FullyQualifiedErrorId : InvokeMethodOnNull
unable to shutdown Windows 10 64 Bit
The problem is that name is not a property of $vm so $vmshut is nothing.
I'm trying to list the properties of $vm but so far am unable to do so.
Trying this:
Write-Host ($vm | Format-List -Force | Out-String)
but nothing is logged.
Kevin
ASKER
Actually, I think name IS a property but it's empty.
Kevin
Kevin
ASKER CERTIFIED SOLUTION
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
No, no, you do not combine write-host and format-* ;-).
If you want to print out things for debugging, just use $vm | Format-List * .That should show all values, even of hidden properties (PS hides a lot from you to make it "easier" for you).
If you want to print out things for debugging, just use $vm | Format-List * .That should show all values, even of hidden properties (PS hides a lot from you to make it "easier" for you).
Yes, I think your WMI query has valid syntax, but does not return a value (nothing found?). Did you cross-check the vm name you get by the prior WMI query?
That seems to be an issue with some Windows versions (mine works, so I can only guess).
Try replacing
$vmname = $vm.name
with
Try replacing
$vmname = $vm.name
with
$vm.__PATH -match '(?<GUID>[a-f0-9]{8}-(?:[a-f0-9]{4}-){3}[a-f0-9]{12})' | Out-Null
$vmname = $Matches['GUID']
ASKER
>Any specific reason you're not just using Stop-VM and Start-VM?
Because I have little to no idea what I am doing and depending on crap on the web.
I built two PowerShell scripts I can call from my batch scripts and they work perfectly:
Stop-VM -Name $args[0] -Force
and
Start-VM -Name $args[0]
The problem with the first PowerShell script was that, beside being uber complicated, the queries were not working. For example, this query just returns the physical box machine, not the Hyper-V virtual machines:
$vm = gwmi -namespace root\virtualization\v2 -query "select * from msvm_computersystem"
So $vm was nothing which is why $vm.name was empty and so on. I'm not sure how it ever worked.
Thank you for simplifying this for me!
Kevin
Because I have little to no idea what I am doing and depending on crap on the web.
I built two PowerShell scripts I can call from my batch scripts and they work perfectly:
Stop-VM -Name $args[0] -Force
and
Start-VM -Name $args[0]
The problem with the first PowerShell script was that, beside being uber complicated, the queries were not working. For example, this query just returns the physical box machine, not the Hyper-V virtual machines:
$vm = gwmi -namespace root\virtualization\v2 -query "select * from msvm_computersystem"
So $vm was nothing which is why $vm.name was empty and so on. I'm not sure how it ever worked.
Thank you for simplifying this for me!
Kevin
As far as "For example, this query just returns the physical box machine, not the Hyper-V virtual machines" is concerned: were you running the script from an elevated console? A regular user won't be allowed to see access virtual machines.
ASKER
Yes. Everything was run as administrator.
function Set-VMs
{
<#
.SYNOPSIS
Short Description
.DESCRIPTION
Detailed Description
.EXAMPLE
Set-VMs
explains how to use the command
can be multiple lines
.EXAMPLE
Set-VMs
another example
can have as many examples as you like
#>
[CmdletBinding()]
param
(
[Parameter(Mandatory=$false, HelpMessage="Time to wait betwen Each VM Start (in seconds)",ValueFromPipeline=$true)]
[int] $waitstart = 200,
[Parameter(Mandatory=$false, HelpMessage="Time to wait between Each VM to Stop (in Seconds)",ValueFromPipeline=$true)]
[int] $waitshutdown = 120,
[Parameter(Mandatory=$true,HelpMessage='Valid options: Connect or Disconnect')]
[ValidateNotNull()]
[ValidateNotNullOrEmpty()]
[ValidateSet('Start', 'Stop')]
[string]$StartStopVM,
[Parameter(Mandatory=$true, ValueFromPipeline=$true)]
[ValidateScript({test-path -path $_ -pathType Leaf})]
[string]$hosts
)
if ($startstopVM -eq 'start')
{
$inputfile=get-content -Path $hosts
foreach ($guest in $inputfile)
{
try{
if ((get-vm -Name $guest | select-object -ExpandProperty State) -eq "Running")
{
Write-Host ('{0} is already running' -f $guest)
}
else
{
Write-Host -Message ('Starting {0}' -f $guest)
try {
start-vm -Name $guest
Write-Verbose -Message ('{0} is started' -f $guest)
}
catch{
Write-Verbose -Message ''
Write-Verbose -Message ('unable to start {0}' -f $guest)
Write-Verbose -Message ''
}
}
}
catch { write-host ("VM $guest does not exist") }
}
}
#not starting must be stopping
else {
$inputfile=get-content -Path $hosts
foreach ($guest in $inputfile) {
Write-Verbose -Message ('shutting down {0}' -f $guest)
try {
stop-vm -Name $guest
Write-Verbose -Message ('no error while shutting down {0}' -f $guest)
Write-Verbose -Message ('shutdown of {0} completed' -f $guest)
Write-Verbose -Message ''
}
catch
{
Write-Verbose -Message ''
Write-Verbose -Message ('unable to shutdown {0}' -f $guest)
Write-Verbose -Message ''
}
}
}
}
ASKER
%SystemRoot%\system32\Wind
and am now getting these errors:
gwmi : Invalid class "msvm_computersystem"
At C:\Users\Kevin Jones\Documents\Scripts\Sc
+ $vm = gwmi -namespace root\virtualization -query "select * from msvm_ ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidType: (:) [Get-WmiObject], ManagementException
+ FullyQualifiedErrorId : GetWMIManagementException,
gwmi : Invalid class "Msvm_ShutdownComponent"
At C:\Users\Kevin Jones\Documents\Scripts\Sc
+ $vmshut = gwmi -namespace root\virtualization -query "SELECT * FROM M ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidType: (:) [Get-WmiObject], ManagementException
+ FullyQualifiedErrorId : GetWMIManagementException,
You cannot call a method on a null-valued expression.
At C:\Users\Kevin Jones\Documents\Scripts\Sc
+ $result = $vmshut.InitiateShutdown("
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidOperation: (:) [], RuntimeException
+ FullyQualifiedErrorId : InvokeMethodOnNull
unable to shutdown Windows 10 64 Bit
Kevin