How can I suspend a Hyper-V VM from a linux machine? - linux

I've set up an NMS system on a machine running Ubuntu that responds to various UPS events by calling a Perl script to go through all of our VMWare hosts and suspend all of the VMs. VMWare was smart and provided a set of Perl modules which made this relatively easy. We also have three Hyper-V hosts, however, and I can't seem to find a way to control them that isn't specific to some Microsoft technology (e.g. a PowerShell script).
I'm hoping somebody could suggest a way to control the Hyper-V hosts from a linux box. I'd rather it didn't involve using Wine, but I'm willing to go that route if there's nothing else that will work.

I found an ugly way to do it, but at least it doesn't require anything to be installed or configured on the VM host.
First I got a utility called winexe, which lets you open a terminal connection to a windows machine.
Then I wrote a long an ugly Perl script to pipe some PowerShell code to the machine to suspend any running machines:
sub hv_suspend_host {
my $host = $_[0];
my $code = <<'END';
echo '===BEGIN'
$query = "SELECT * FROM Msvm_ComputerSystem WHERE EnabledState != 3 AND EnabledState != 32769" #Exclude off and saved VMs
$VMs = get-wmiobject -query $query -namespace "root\virtualization" -computername "."
foreach ($VM in $VMs) {
if ($VM.name -ne $VM.ElementName) { # Exclude the host itself
if ($VM.RequestStateChange(32769).ReturnValue -eq 4096) { # Put the VM in a saved state
# It worked, log success
} else {
# It didn't, log failure
}
}
}
echo '===END'
exit
END
my $recv;
run(["winexe", '-U', "DOMAIN/$win_user%$win_pass", '--interactive=0', "//$host", 'powershell -command -'], \$code, \$recv);
$recv =~ tr/\r//d; # Convert to UNIX line endings
$recv =~ /===BEGIN\n(.+)===END/s; # Now recv contains anything you logged
}
You might have to mess with this a bit to get it to work. I had to hack out some of the implementation-specific things, but I left in part of the output capturing code. This requires global variables named $win_user and $win_pass containing administrator account login info for the target VM host. It also requires that you use IPC::Run.

Hyper-V can be managed remotely using the WMI interfaces. There is a WMI Client for Linux, which should allow you to make the relevant API calls to manage Hyper-V. I have not had to do this myself, but the specific WMI calls are available at Microsoft: https://msdn.microsoft.com/en-us/library/hh850319%28v=vs.85%29.aspx

Related

Cross talk threads to allow for file system access in powershell

Reference: Runspace for button event in powershell
https://www.foxdeploy.com/blog/part-v-powershell-guis-responsive-apps-with-progress-bars.html
So, I believe my issue is that PowerShell is unable to access the memory space of the file system, from within the memory block, of my thread, is there a way to solve this, to access the file system, from a multi-threaded application?
Back Story:
So, I run a program, that calls upon "code"/command, from the command prompt, (*.exe) (Robocopy) to copy files from a server, to a group of computers, at a time. We have a classroom environment, at my work, so I have my setup, in a way, that I have a folder, per room. I keep a list of all our addresses (static), for each room, in their perspective folders. We have an update, from our developers, that we need to push to all of the rooms. We need to run a slow push, as to not disturb the production environment. It's proprietary, so we can't use a/any typical solution(s), like Microsoft SCCM. So, I created a script to push to the rooms. while it does work, it's not a smooth operation. I'm not actually the one pushing the update, because of the slow process, of updating. I'm just trying to make a stable smooth-running package, for the person, who is going to be doing it. My code works, outside of the thread, (I) tested it, I know it works.
So how I came my conclusion of knowing, that my code works outside of the thread. (The picture) I followed the same setup, with my code, (A button click event inside of a thread, running the form). Placed the actual working code, (tried, and tested, before making a Thread, for the interface, after completing backend operation code testing.)
("Region Boe's Addition") referring to Boe Prox, (from the link)
In his, he is updating from a command line/powershell window, via a function run inside a thread. I'm running an event from a button, inside of a thread and trying to run a separate thread, for the click event(s). Outside of the thread. The event works fine, but inside, it doesn't work, at all..
Basic Code:
// Multi thread, thread for the $form, and thread for the event (as per referenced link)
$var = [PowerShell]::Create().AddScript({ button.Add_Click{
$var = [PowerShell]::Create().AddScript{<Thread><Robocopy></Thread>}
})
Needed the "Start-Process" -Wait command to allow for the listbox, to be updated in-between copies, to confirm installation, through each step in the loop.
$choice = $comboBox.SelectedItem
# $drive = Get-Location
if(!(Test-Path -PathType Container -Path "L:\$choice"))
{
# New-Item -ItemType "container" -Path . -Name $choice
New-Item -ItemType "Directory" -Path . -Name $choice
}
# $folder = $_
# Where is it being stored at?
[System.IO.File]::ReadLines("Y:\$choice\IPs.txt") | foreach {
ping -a -n 2 -w 2000 $_ | Out-Null
Test-Connection -Count 2 -TimeToLive 2 $_ | Out-Null
if($?)
{
RoboCopy /Log:"L:\$folder\$_.log" $source \\$_\c$\tools
RoboCopy /Log+:"L:\$folder\$folder-MovementLogs.log" $source \\$_\c$\tools
Start-Process -Wait "P:\psexec.exe" -ArgumentList "\\$_ -d -e -h -s cmd /c reg import C:\tools\dump.reg"
# Copy-Item -LiteralPath Y:\* -Destination \\$_\c$\tools
$listBox.Items.Add($_)
}
}

Disable/enable completely input devices (mouse+keyboard+touchpad) in Windows10

I'm trying to disable/enable input devices in my laptop (win10), automatically (.reg file, python code etc)
I tried to use DevCon but after a lot of attempts it didn't work out for my touchpad and keyboard (I tried to disable, remove).
I searched the web and the solutions don't completely disable the devices (for example: Ctrl+Alt+Delete is not blocked).
I work on a windows 10 Laptop, You can assume that you have admin Privileges.
Have to check for Keyboard but for Mouse and Touchpad, you can use some Powershell commands to check and find out the actual device Classes and InstanceIDs and then turn off with an Admin elevated Powershell prompt.
The InstanceIDs of Mouse and Touchpad is different on different brands and types of Laptops, but first you can identify those with their Classes such as HIDClass. To get that fire up Powershell prompt(you've already tried REG and Python, so assuming you'll be okay with Powershell too (.ps1)) and run this command:
Get-PnpDevice | Where-Object {$_.Class -eq 'HIDClass'}
This may show 2 or 3 entries of which 1 belongs to Mouse and other to Touchpad, this would be a bit of trial and error, you have to pick any InstanceID to make filter more target specific and fire-up admin-elevated Powershell (search Powershell and click on "Run As Administrator") and run Disable-PnpDevice method like below(if InstanceId contains "ACPI"):
Get-PnpDevice | Where-Object {$_.Class -eq 'HIDClass' -and $_.InstanceId -like 'ACPI*'} | Disable-PnpDevice -Confirm:$false
This will disable Touchpad(in mine(Lenovo) it did disabled it) and then you can try out another InstanceID and disable the Mouse too in the same way. Voila !! both are turned off now.
If you prefer this in .ps1 script format then you need a self-elevating script which can enable/disable the devices without any halts, save this code in .ps1 file and then right-click > Run with PowerShell:
$Loc = Get-Location
"Security.Principal.Windows" | % { IEX "( [ $_`Principal ] [$_`Identity ]::GetCurrent() ).IsInRole( 'Administrator' )" } | ? {
$True | % { $Arguments = #('-NoProfile','-ExecutionPolicy Bypass','-NoExit','-File',"`"$($MyInvocation.MyCommand.Path)`"","\`"$Loc\`"");
Start-Process -FilePath PowerShell.exe -Verb RunAs -ArgumentList $Arguments; } }
Get-PnpDevice | Where-Object {$_.Class -eq 'HIDClass' -and $_.InstanceId -like 'ACPI*'} | Disable-PnpDevice -Confirm:$false
Read-Host
Note: If you in case disable the wrong or undesired device than for enabling it, in the same admin-elevated Powershell window run the same filter command (the Get-PnpDevice with filters) and replace Disable-PnpDevice with Enable-PnpDevice.
Let me know in comments if you still face issue with above commands.
Untested, but calling BlockInput() should do what you want. It blocks both keyboad and mouse input. It is however defined in user32.dll so you will need to use ctypes to access it:
import ctypes
ctypes.windll.user32.BlockInput(True)

How to Pass commands to custom linux Service using bash / terminal

Goal: Run a custom bash script as a service in linux and allow me to pass commands to it like you can to most other services via terminal/bash.
I already have a script set up and tested that can do what I need it to, except I can't figure out how to be able to pass commands to it like you would other services.
Example: nano opens up the nano editor to read specified file.
I want to perform 'fan on', which will call the new service 'fan' and execute the 'on' command.
Bonus: Being able to save the variables into a config file to be modified later on. But for now, I have the variables set at top of script so its not totally necessary.
Current Unit File:
[Unit]
Description=Fan control Service
[Service]
Type=simple
Restart=always
RestartSec=30
ExecStart=/home/pi/Documents/FanControl.sh
User=pi
[Install]
WantedBy=multi-user.target
Script:
#!/bin/bash
#########################################################
# User Settings
#GPIO Pin Number to use to control fan transistor.
fanpin=3
#Celsius temp to turn fan on/off
offtemp=55
ontemp=60
#Turn on the looping script automatically or not
autostart=TRUE
#Determine how often to scan temp and turn fan on/off if in auto
sleepinterval=10
#########################################################
#Misc Variables used in script - Leave these alone - Base Settings
MaxTemp=0
FanState=OFF
mode=MANUAL
auto=FALSE
#########################################################
# Functions Described Below
#########################################################
before-start() {
# Check if gpio is already exported
if [ ! -d /sys/class/gpio/gpio$fanpin ]
then
#Export the Pin
echo $fanpin > /sys/class/gpio/export
sleep 1 ;# Short delay while GPIO permissions are set up
echo Fan Pin Exported Successfully.
# Setup the pin as an output
sudo echo "out" > /sys/class/gpio/gpio$fanpin/direction
fi
}
#Function to turn fan on
on() {
# Sets FanPin to high
echo "1" > /sys/class/gpio/gpio$fanpin/value
FanState=ON
mode=Manual
auto=FALSE
echo Fan Turned on -- Mode set to Manual.
echo
}
#Function to turn fan off
off() {
# Sets FanPin to low
echo "0" > /sys/class/gpio/gpio$fanpin/value
FanState=OFF
mode=Manual
auto=FALSE
echo Fan Turned off -- Mode set to Manual.
echo
}
#Function to set the variables to values
#Haven't actually tested this function yet
Set() {
if $2 = "ontemp"
then
ontemp=$2
else
$2=$3
fi
}
#########################################################
# Begin Service Execution Code
#########################################################
#Don't know whow to write this section to keep it running as a service
#But it works well for testing purposes
before-start
on
sleep 3
off
echo
read -p "Select an action": Q
$Q
echo
action="$1"
serviceName="Fan-Control Service"
echo Exiting Fan Service
I can use systemctl daemon-reload and it can load the service.
I can use 'systemctl start fan' and the service starts successfully without error. it will also run the fan for a few seconds, so i know its starting fine.
When attempting to use 'fan on' as a bash command, i get "command not found"
- how can i get this as a working command?
- what changes do I need in the script to keep it alive to be able to pass such commands to it later on?
It is atypical for services to respond to interactive commands other than service-management commands drawn from a pre-defined set. If that's the concept you are trying to prove then I would suggest choosing a different direction.
But if you must do it, then you have viable alternatives:
for an on / off toggle, consider setting up a signal handler in the service script, say for SIGUSR1. You can send signals directly via the kill command, but I would recommend instead providing a separate script for the purpose.
for more complex instructions or more than a very small number of distinct instructions, you need some kind of communication channel. The script could potentially use a FIFO or a socket for this purpose, and in that case I would again recommend a separate script for sending commands. But this will require your service to be substantially more complex.
In any case, do note that although there's a long tradition of service-control scripts, service implementations themselves are rarely scripts. They are normally compiled programs, typically written in C, as this provides more direct access to the system and finer control, and is also considered by many to be more secure (when done competently).

Stop IIS express process based on site name

The site im working on got 3 individual sites running on the IIS.
When I make changes to on particular library I need to restart the site using it. The way I do that now is by manually rightclicking the IIS Express icon in the system tray, and then clicking 'Stop site', and after that I execute the debugging..
I would like to make that part automatic, so when ever i start debugging it will stop that particular site.
If I don't stop it, then it will just reuse the current running site, but if I stop it, then it will restart it..
Is it event posible? I know how to find the PID, but I don't get the name of the site behind the PID..
I put together this script in PowerShell:
$site = 'Webapplication' # replace this by your site name (not case sensitive)
$process = Get-CimInstance Win32_Process -Filter "Name = 'iisexpress.exe'" | ? {$_.CommandLine -like "*/site:`"$site`"*" }
if($process -ne $null)
{
Write-Host "Trying to stop $($process.CommandLine)"
Stop-Process -Id $process.ProcessId
Start-Sleep -Seconds 1 # Wait 1 second for good measure
Write-Host "Process was stopped"
} else
{
Write-Host "Website was not running"
}
Modify the first line to replace the site name with yours. Save this
file as stopiis.ps1 on your project folder (not the solution folder).
Now, on Solution Explorer, right-click and choose properties
On the left side, choose Build Events
Put this on 'Pre-Build event command line' so it will run before compiling:
echo powershell -File "$(ProjectDir)stopiis.ps1"
powershell -File "$(ProjectDir)stopiis.ps1"
Note: you do not need to run Visual Studio in Administrative mode because IISExpress.exe run under your account

Nagios verify Sharepoint

I want to set Nagios (on my Debian) to verify a SharePoint server is up. I already tried to use cURL but it didn't worked for some issue that I don't know so I decided to change the way I'll verify that service.
It's simple in theory, I just have to make a script to send an request (http or https, doesn't matter) and check the response, if is 200 for successful or 40x if not (ok at this point).
So I have to use telnet or any ftp service to do that or I can use another feature/tool for that.
With telnet I'am having problem with 400 error. SharePoint returns this error when server is up or down, so I don't work for me.
Any ideas??
You can use the check_http plugin of Nagios. For example:
check_http -H SharepointHostname/IP -p port
You can use the -S flag for secure http connections
You can use the -u flag for going to specific URL
You can use the -s flag to search for a specific string in the HTML page returned from the url specified with the -u flag.
So basically you can request a specific page, scan for a known String, and if successfully found, you are sure this page is up (which means server is up etc.)
Example:
check_http -H my.sharepoint.com -u /start/page/sharepoint.aspx -s "test string"
Commonly this is done on login pages etc. Don't forget to escape special chars in your URL, if it contains any (like ? and &).
There's also a perl script available for checking sharepoint servers.
Does this not do what you want:
http://exchange.nagios.org/directory/Plugins/Email-and-Groupware/Microsoft-Sharepoint/check_sharepoint-2Epl/details
Most likely you're going to need a login/password for Sharepoint in order to monitor much more than the basic IIS / website is working.
I done my own way to check if SharePoint is UP or DOWN. Please pay attention that this script just checks the service status, nothing more like user permissions or whatever.
Perl script:
#!/usr/bin/env perl
use strict;
use warnings;
use LWP::UserAgent;
use Getopt::Long qw(:config no_ignore_case_always auto_version);
GetOptions ('h=s' => \my $h);
my $ua = LWP::UserAgent->new;
$ua->agent('Mozilla/4.0 (compatible; MSIE 5.0; Windows 95)');
my $req = $ua->get('http://' . $h);
my $retorno = '';
if ($req->is_success)
{
$retorno = $req->content;
}
else
{
$retorno = $req->status_line;
}
if ($retorno eq "401 Unauthorized")
{
print "OK: SharePoint service at " . $h . " server is UP.";
exit 0;
}
else
{
print "CRITICAL: SharePoint service at " . $h . " server is DOWN.";
exit 2;
}
In case you got this exception when you run the script:
Can't locate LWP/UserAgent.pm in #INC
this article may help you as it helped me:
http://help.directadmin.com/item.php?id=274
So in Nagios commands.cfg file you'll declare the command this way:
command_line /usr/local/nagios/libexec/check_sharepoint.pl -h $HOSTADDRESS$
Where $HOSTADDRESS is the host IP variable in Nagios scope.
Remember to chmod +x on the file. I know you will...

Resources