Archive | Powershell RSS for this section

Set Hyper-V VM Resynchronization Schedule via PowerShell

We were recently working through a multi-site Hyper-V VDI deployment for a customer and needed to set the Hyper-V replica ReSync Schedule for all VM’s and ensure that Auto Resync was enabled.  Per Host, this was accomplished by running the following script:

get-vm | Where-Object ReplicationMode -EQ “Primary” | Set-VMReplication -AutoResynchronizeEnabled $True -AutoResynchronizeIntervalStart “00:00:00” -AutoResynchronizeIntervalEnd “23:59:59”


For all VM’s, we used the following script:

$HVHOSTS = Get-ADComputer -Filter {Name -like “*host*” -and Name -notlike “*hvhost*”} | Select -ExpandProperty Name #NOTE: Your filter will look different , adjust to suit
foreach ($HVHOST in $HVHOSTS){
$VMs = get-vm -ComputerName $HVHOST | Where-Object ReplicationMode -eq “Primary”
foreach ($VM in $VMs){

Set-VMReplication -ComputerName $HVHOST -VMName $VM.Name -AutoResynchronizeEnabled $True -AutoResynchronizeIntervalStart “00:00:00” -AutoResynchronizeIntervalEnd “23:59:59”



Disclaimer: As with any script – please review & lab test in your own environment, before rolling out to production! 🙂

Check disk space remotely with PowerShell

I work with a customer with a large VDI environment.  They had asked for a weekly report to generate with an overview of VDI disk free space.  I have created the script below to do just that.

Effectively it has three parameters (ie Get-DiskSpaceReport.ps1 – To – SMTPServer -From  It runs against the AD Computer filter specified in the script (in my case it’s computers with the name VDI in it).   After the report is ran, you receive an e-mail with the results sorted by % Free:


This is the result:

Param (

Import-Module ActiveDirectory
$VDISearch = get-adcomputer -filter * | Where-Object Name -Like *VDI* #Change this filter to suit your needs

$VDIs = $VDISearch.Name
$Results = @()
foreach ($VDI in $VDIs){
$disk = Get-WmiObject win32_logicaldisk -ComputerName $VDI -Filter “Drivetype=3” -ErrorAction SilentlyContinue
$Results += New-Object PSObject -Property @{
‘VDI’ = $Disk.SystemName
‘Drive Letter’ = $Disk.DeviceID + ‘\’
‘Free Space (GB)’ = ((“{0:N1}” -f ($Disk.FreeSpace/1GB)) + ‘ GB’)
‘% Free’ = ((“{0,6:P0}” -f (($Disk.FreeSpace/1GB)/($Disk.Size/1GB)) ))

$Header = @”
TABLE {border-width: 1px;border-style: solid;border-color: black;border-collapse: collapse;}
TH {border-width: 1px;padding: 3px;border-style: solid;border-color: black;background-color: #6495ED;}
TD {border-width: 1px;padding: 3px;border-style: solid;border-color: black;}

$splat = @{
From = $From
To = $To
SMTPServer = $SMTPServer
Subject = “VDI Disk Space Report Generated by $env:computername”

$Results = $Results | Select ‘VDI’, ‘Drive Letter’, ‘Free Space (GB)’,’% Free’ | Sort ‘% Free’

$Body = $Results | ConvertTo-Html -Head $Header | Out-String

Send-MailMessage @splat -Body $Body -BodyAsHTML


Check registry for key value for remote servers/computers

I’ve had a couple of requests from customers this week to check for the presence of a specific registry key.  One looking for 2008/2008R2 servers: Get-ADComputer -Filter {OperatingSystem -Like “Windows Server* 2008”} -Properties * or others against a security group : Get-ADComputer -filter * -Property * | where {$_.memberof -match ‘YOURGROUPNAMEHERE’}.  Here’s a sample of it to check for all systems with .NET 4.6.2 installed and outputs it to a text file:

$RemoteSystems= Get-ADComputer -filter * -Property *
$RemoteHosts = $RemoteSystems.Name

foreach ($RemoteHost in $RemoteHosts){
$Hive = [Microsoft.Win32.RegistryHive]”LocalMachine”;
$RegKey = [Microsoft.Win32.RegistryKey]::OpenRemoteBaseKey($Hive,$RemoteHost);
$Ref = $RegKey.OpenSubKey(“SOFTWARE\Microsoft\NET Framework Setup\NDP\v4\Full\”);
$RefValue = $Ref.GetValue(“Release”)
if ($RefValue -ge “394806”){$PatchStatus.Add($RemoteHost,”Patched”)}
else {$PatchStatus.Add($RemoteHost,”Needs .NET”)}

$PatchStatus | Out-File “C:\Temp\Needs-DotNET4.6.2.txt”

PowerShell Script to Move Hyper-V VM’s

Quick easy PowerShell script to move VM’s from one Hyper-V host to another:

Get-VM -computer SOURCESERVERNAME | Out-GridView -Title “Select one or more VMs to Live Migrate” -PassThru | Move-VM -DestinationHost DESTINATIONSERVERNAME -DestinationStoragePath J:\Hyper-V (Or whatever your destination path is)

Find all HP Proliant Server Product Numbers/ID & Serial Number in Active Directory

I recently needed to find a way to look for all HP Proliant Servers in an organization for Warranty reporting.   I put the following script together for this purpose.  The script builds a Data Table, searches AD for all servers, confirms they are not a Virtual Machines & are Proliant servers, then runs a WMI query to pull the Product ID (and formats the output) & Serial Number into the ServerReport Table.  This in turn is exported to a formatted CSV file. This can be plugged into something like this to expand further.

Here is the script:

#Please place the full path to your output file. Ie. C:\temp\myservers.csv
$FileOutputPath = “C:\temp\myservers.csv”
$ServerReport = new-object “ServerReport”;
$ServerReport.columns.add((new-object “ServerName”, ([string])));
$ServerReport.columns.add((new-object “ServerSerial”, ([string])));
$ServerReport.columns.add((new-object “ServerProduct”, ([string])));

$Serverlist = Get-ADComputer -Filter {OperatingSystem -Like “Windows *Server*”} -Property * | select-object -ExpandProperty Name
foreach($Server in $Serverlist){

$ComputerModel = (Get-WmiObject -Class Win32_ComputerSystem -ComputerName “$server” -ErrorAction Ignore | Select-Object Model).Model

if ($ComputerModel -match “Virtual Machine”) {
write-host “$Server is a Virtual Machine, moving to next Server”

if ($ComputerModel -like “*Proliant*”) {
$SerialNumberNoFormat = (Get-WmiObject -Class Win32_BIOS -ComputerName “$server” | Select-Object SerialNumber).SerialNumber
$SerialNumber = $SerialNumberNoFormat -replace “[^a-zA-Z0-9]”
$OEMStringArray = (Get-WmiObject -Class Win32_ComputerSystem -ComputerName “$server” | select -ExpandProperty OEMStringArray)
$ProductNumberNoFormat = $OEMStringArray -replace “[^0-9-]”
$ProductNumber = $ProductNumberNoFormat.Split(“;”,[System.StringSplitOptions]::RemoveEmptyEntries)
$row = $ServerReport.NewRow()
$row.”ServerName” = $Server
$row.”ServerSerial” = $SerialNumber
$row.”ServerProduct” = $ProductNumber

write-host “$Server is an HP Proliant Server, Serial Number $SerialNumber & Product Number $ProductNumber are being added to file $FileOutputPath”

$ServerReport | Export-CSV -path $FileOutputPath -Append -NoTypeInformation


Hope it helps!

Check for open application and reboot Hyper-V VM

I’ve recently had a requirement for a scheduled reboot of a large group of Hyper-V VDIs. Due to the nature of the line of business application, it was imperative that we checked that several specific apps were not running before the reboot was ran.  Here is an example of the script I wrote for this task.  Simply replace the $process, $process2, etc. with your specific application (name only, no path or .exe, etc. requirement).  The script checks the running process on the VDI, if one of the apps are running it breaks the loop for that VM and continues to the next, otherwise it reboots the VM and notifies the user.  Here’s the script:

$vms2reboot = get-vm | Where-Object Name -like *test-vm001* | Select-Object -Expand Name
$process = “Notepad”
$process2 = “Calc”
$process3 = “Mspaint”
start-transcript “C:\reboot-vms.log”
foreach ($vm2reboot in $vms2reboot){

if(get-process -Computername $vm2reboot | where-object {
$_.ProcessName -contains “$process” -or
$_.ProcessName -contains “$process2”-or
$_.ProcessName -contains “$process3”
Write-Host “A business app is currently running.  Reboot will not continue on $vm2reboot”
Else {write-host “Rebooting VM $vm2reboot”
shutdown -r -f -m \\$vm2reboot -c “Reboot commencing for maintenance”


10-04-2015 9-10-51 p-m-new

If one of the apps are open, reboot does not continue:

10-04-2015 9-16-53 p-m-

Otherwise it reboots the VM:

10-04-2015 9-15-12 p-m-

10-04-2015 9-14-37 p-m-


Check time source for all Domain Controllers

I was recently working on an issue for a customer who was noticing random time sync issues on various DC’s.  I needed to confirm that all servers were set to point to the PDC for their time source.  I’ve put together this basic script which does just that:
9-04-2015 12-16-18 p-m-
$DomainControllers =  Get-ADDomainController -Filter * | Select-Object -expand name
foreach ($DomainController in $DomainControllers)
write-host “———————————————–”
write-host “Domain Controller: $DomainController”
write-host “Time Source:”
w32tm /query /computer:$DomainController /source
write-host “———————————————–”


Bulk Fortigate configuration backup

Continuing on from the previous post with bulk management of firewalls, in particular Fortigates.  The following shows a basic script which after enabling SCP transfers on your device, utilizes pscp.exe to backup multiple Fortigate firewall configs.

This script gets the current date, creates a folder under your Backup Path with the date, connects to each firewall in your CSV file (just as the previous post) and uses pscp.exe to backup the config file (fgt-config).  It then renames the fgt-config output file to the IP of your firewall and appends the date to the file name.  I am utilizing the echo y command at the front of the command to accept the untrusted certificate error at first connection.  In a production environment you may wish to re-evaluate this option!

Note, while the transcript option is present, due to a bug in PowerShell you do not get a whole lot of info out of running cmd applications from PowerShell.  I’ll look at a work around for this and update in the near future.

$Firewalls = get-content .\firewalls.csv
$Date = Get-Date -Format “dd-MM-yyyy”
$Username = “firewallusername”
$Password = “firewallpassword”
$BackupPath = “E:\Firewall-Config-Backups”
New-Item $BackupPath\$Date\ -type directory
Start-Transcript -path $BackupPath\$Date\$Date.log -append

foreach ($Firewall in $Firewalls){

echo y | .\pscp.exe -l $Username -pw $Password -v “$Firewall::fgt-config” $BackupPath\$Date\ | out-host -verbose
rename-item -path $BackupPath\$Date\fgt-config -newname $BackupPath\$Date\$Firewall-$Date.conf



Here’s what your final screen output should look like:


Using Powershell for bulk SSH commands on Fortigate firewalls, etc.

I’ve been working with a customer with a large stack of Fortigate firewalls.  Quite frequently there is a requirement to run commands against some or all of the firewalls.  While config management can be performed via the FortiManager, after trialling it we realized there were simply too many limitations for their requirements.  Thankfully bulk commands can be performed with this handy PowerShell SSH Module:  As an example, I’ve built a quick power shell script as an example of how this can be used.

1.) Populate a list of your firewall IP addresses in a CSV firewall called Firewalls.csv.
2.) Example: Enable SCP on Fortigate firewalls (to be used in a running config backups, etc.)
Import-Module .\SSH-Sessions.psd1
$Firewalls = get-content .\firewalls.csv
$Username = “firewallusername”
$Password = “firewallpassword”
foreach ($Firewall in $Firewalls){
New-SshSession $Firewall -Username $Username -Password $Password
Invoke-SshCommand $Firewall -command ‘config system global
set admin-scp enable


Note: In a production environment you would want to a) Use Cert based authentication or b) Encrypt your User/Name password (or perhaps prompt for a credential when script is ran).  It goes without saying – backup your firewall config before you make any changes! 🙂

In my next post I’ll cover using pscp.exe to backup your firewall config in a PowerShell script.

Create Hyper-V VDI/VM by name from CSV file

I was working on a Hyper-V VDI project for a customer recently, who needed to easily deploy a VDI Template VHD from a CSV file and create VMs based on this VHD. I put this script together to fit this requirement.

It references a CSV file called vdi.csv, which contains your desired Hyper-V VM names.  It then builds as many copies of the VM as your CSV contains:
Here’s the script!
$VDIs = get-content .\vdi.csv
foreach ($VDI in $VDIs){
write-host $VDI is being copied from a VHD template.  This will take approxmiately 2 minutes…
copy “F:\Hyper-V\Virtual Hard Disks\vdi-template.vhd” “F:\Hyper-V\Virtual Hard Disks\$VDI.vhd”
New-VM -Name $VDI -BootDevice IDE -VHDPath “F:\Hyper-V\Virtual Hard Disks\$VDI.vhd” -MemoryStartupBytes 2GB -SwitchName “External”
Set-VMMemory -VMName $VDI -DynamicMemoryEnabled $true -MinimumBytes 512MB -StartupBytes 2GB -MaximumBytes 4GB
Set-VM -Name $VDI -AutomaticStopAction Shutdown
write-host $VDI Has now been created and ready for use…
It’s a quick and dirty script – I’ll look at building it out as future requirements dictate.