PowerShell: Add and Remove a Registry Key

How to Add a Registry Key

# Add New Registry Key
$regHive='REGISTRY::HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\MSCRM'
$keyname='OleDbTimeout'
$value=600
Set-ItemProperty -Path $regHive -Name $keyname -value $value

# Validation
Get-ItemProperty $regHive -name $keyname

PS C:\Users\backupadmin> Get-ItemProperty $regHive -name $keyname
OleDbTimeout : 600
PSPath       : Microsoft.PowerShell.Core\Registry::HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\MSCRM
PSParentPath : Microsoft.PowerShell.Core\Registry::HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft
PSChildName  : MSCRM
PSProvider   : Microsoft.PowerShell.Core\Registry

How to Remove a Registry Key

# Remove Registry Key
$regHive='REGISTRY::HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\MSCRM'
$keyname='OleDbTimeout'
Remove-ItemProperty -Path $regHive -Name $keyname -value $value

How to Repair Windows Corrupted System Files

Check for Corruptions

# Check for corrupted system files
Dism /Online /Cleanup-Image /ScanHealth

[TESTWINDOWS001]: PS C:\Users\backupadmin\Documents> Dism /Online /Cleanup-Image /ScanHealth

Deployment Image Servicing and Management tool
Version: 10.0.14393.4169
Image Version: 10.0.14393.4169
[==                         5.0%                           ]
---- and a long wait ----
[==========================100.0%==========================]
No component store corruption detected.
The operation completed successfully.

Perform Repairs

# Perform repairs
Dism /Online /Cleanup-Image /RestoreHealth

[TESTWINDOWS001]: PS C:\Users\backupadmin\Documents> Dism /Online /Cleanup-Image /RestoreHealth
Deployment Image Servicing and Management tool
Version: 10.0.14393.4169
Image Version: 10.0.14393.4169
[==                         4.5%                           ]
---- and a long wait ----
[==========================100.0%==========================]
The restore operation completed successfully.
The operation completed successfully.

Legacy Commands

# Legacy corrupted system files repair
SFC /scannow

# Sample output
[TESTWINDOWS001]: PS C:\Users\backupadmin\Documents> SFC /scannow

 B e g i n n i n g   s y s t e m   s c a n .     T h i s   p r o c e s s   w i l l   t a k e   s o m e   t i m e .

 B e g i n n i n g   v e r i f i c a t i o n   p h a s e   o f   s y s t e m   s c a n .

 V e r i f i c a t i o n   0 %   c o m p l e t e . V e r i f i c a t i o n   0 %   c o m p l e t e . V e r i f i c a t i o n   1 %   c o m p l e t e . V e r i f i c
t i o n   1 %   c o m p l e t e . V e r i f i c a t i o n   1 %   c o m p l e t e . V e r i f i c a t i o n   2 %   c o m p l e t e . V e r i f i c a t i o n   2 %
c o m p l e t e . V e r i f i c a t i o n   3 %   c o m p l e t e . V e r i f i c a t i o n   3 %   c o m p l e t e . V e r i f i c a t i o n   3 %   c o m p l e t e
. V e r i f i c a t i o n   4 %   c o m p l e t e . V e r i f i c a t i o n   4 %   c o m p l e t e . V e r i f i c a t i o n   4 %   c o m p l e t e . V e r i f i c
a t i o n   5 %   c o m p l e t e . V e r i f i c a t i o n   5 %   c o m p l e t e . V e r i f i c a t i o n   6 %   c o m p l e t e . V e r i f i c a t i o n   6 %
  c o m p l e t e . V e r i f i c a t i o n   6 %   c o m p l e t e . V e r i f i c a t i o n   7 %   c o m p l e t e . V e r i f i c a t i o n   7 %   c o m p l e t
e . V e r i f i c a t i o n   7 %   c o m p l e t e . V e r i f i c a t i o n   8 %   c o m p l e t e . V e r i f i c a t i o n   8 %   c o m p l e t e . V e r i f i
c a t i o n   9 %   c o m p l e t e . V e r i f i c a t i o n   9 %   c o m p l e t e . V e r i f i c a t i o n   9 %   c o m p l e t e . V e r i f i c a t i o n   1
0 %   c o m p l e t e . V e r i f i c a t i o n   1 0 %   c o m p l e t e . V e r i f i c a t i o n   1 0 %   c o m p l e t e . V e r i f i c a t i o n   1 1 %   c o
m p l e t e . V e r i f i c a t i o n   1 1 %   c o m p l e t e . V e r i f i c a t i o n   1 2 %   c o m p l e t e . V e r i f i c a t i o n   1 2 %   c o m p l e t
e . V e r i f i c a t i o n   1 2 %   c o m p l e t e . V e r i f i c a t i o n   1 3 %   c o m p l e t e . V e r i f i c a t i o n   1 3 %   c o m p l e t e . V e r
i f i c a t i o n   1 3 %   c o m p l e t e . V e r i f i c a t i o n   1 4 %   c o m p l e t e . V e r i f i c a t i o n   1 4 %   c o m p l e t e . V e r i f i c a
t i o n   1 5 %   c o m p l e t e . V e r i f i c a t i o n   1 5 %   c o m p l e t e . V e r i f i c a t i o n   1 5 %   c o m p l e t e . V e r i f i c a t i o n
1 6 %   c o m p l e t e . V e r i f i c a t i o n   1 6 %   c o m p l e t e . V e r i f i c a t i o n   1 6 %   c o m p l e t e . V e r i f i c a t i o n   1 7 %   c
o m p l e t e . V e r i f i c a t i o n   1 7 %   c o m p l e t e . V e r i f i c a t i o n   1 8 %   c o m p l e t e . V e r i f i c a t i o n   1 8 %   c o m p l e
t e . V e r i f i c a t i o n   1 8 %   c o m p l e t e . V e r i f i c a t i o n   1 9 %   c o m p l e t e . V e r i f i c a t i o n   1 9 %   c o m p l e t e . V e
r i f i c a t i o n   2 0 %   c o m p l e t e . V e r i f i c a t i o n   2 0 %   c o m p l e t e . V e r i f i c a t i o n   2 0 %   c o m p l e t e . V e r i f i c
a t i o n   2 1 %   c o m p l e t e . V e r i f i c a t i o n   2 1 %   c o m p l e t e . V e r i f i c a t i o n   2 1 %   c o m p l e t e . V e r i f i c a t i o n
  2 2 %   c o m p l e t e . V e r i f i c a t i o n   2 2 %   c o m p l e t e . V e r i f i c a t i o n   2 3 %   c o m p l e t e . V e r i f i c a t i o n   2 3 %
c o m p l e t e . V e r i f i c a t i o n   2 3 %   c o m p l e t e . V e r i f i c a t i o n   2 4 %   c o m p l e t e . V e r i f i c a t i o n   2 4 %   c o m p l
e t e . V e r i f i c a t i o n   2 4 %   c o m p l e t e . V e r i f i c a t i o n   2 5 %   c o m p l e t e . V e r i f i c a t i o n   2 5 %   c o m p l e t e . V
e r i f i c a t i o n   2 6 %   c o m p l e t e . V e r i f i c a t i o n   2 6 %   c o m p l e t e . V e r i f i c a t i o n   2 6 %   c o m p l e t e . V e r i f i
c a t i o n   2 7 %   c o m p l e t e . V e r i f i c a t i o n   2 7 %   c o m p l e t e . V e r i f i c a t i o n   2 7 %   c o m p l e t e . V e r i f i c a t i o
n   2 8 %   c o m p l e t e . V e r i f i c a t i o n   2 8 %   c o m p l e t e . V e r i f i c a t i o n   2 9 %   c o m p l e t e . V e r i f i c a t i o n   2 9 %
  c o m p l e t e . V e r i f i c a t i o n   2 9 %   c o m p l e t e . V e r i f i c a t i o n   3 0 %   c o m p l e t e . V e r i f i c a t i o n   3 0 %   c o m p
l e t e . V e r i f i c a t i o n   3 0 %   c o m p l e t e . V e r i f i c a t i o n   3 1 %   c o m p l e t e . V e r i f i c a t i o n   3 1 %   c o m p l e t e .
V e r i f i c a t i o n   3 2 %   c o m p l e t e . V e r i f i c a t i o n   3 2 %   c o m p l e t e . V e r i f i c a t i o n   3 2 %   c o m p l e t e . V e r i f
i c a t i o n   3 3 %   c o m p l e t e . V e r i f i c a t i o n   3 3 %   c o m p l e t e . V e r i f i c a t i o n   3 3 %   c o m p l e t e . V e r i f i c a t i
o n   3 4 %   c o m p l e t e . V e r i f i c a t i o n   3 4 %   c o m p l e t e . V e r i f i c a t i o n   3 5 %   c o m p l e t e . V e r i f i c a t i o n   3 5
%   c o m p l e t e . V e r i f i c a t i o n   3 5 %   c o m p l e t e . V e r i f i c a t i o n   3 6 %   c o m p l e t e . V e r i f i c a t i o n   3 6 %   c o m
p l e t e . V e r i f i c a t i o n   3 6 %   c o m p l e t e . V e r i f i c a t i o n   3 7 %   c o m p l e t e . V e r i f i c a t i o n   3 7 %   c o m p l e t e
. V e r i f i c a t i o n   3 8 %   c o m p l e t e . V e r i f i c a t i o n   3 8 %   c o m p l e t e . V e r i f i c a t i o n   3 8 %   c o m p l e t e . V e r i
f i c a t i o n   3 9 %   c o m p l e t e . V e r i f i c a t i o n   3 9 %   c o m p l e t e . V e r i f i c a t i o n   4 0 %   c o m p l e t e . V e r i f i c a t
i o n   4 0 %   c o m p l e t e . V e r i f i c a t i o n   4 0 %   c o m p l e t e . V e r i f i c a t i o n   4 1 %   c o m p l e t e . V e r i f i c a t i o n   4
1 %   c o m p l e t e . V e r i f i c a t i o n   4 1 %   c o m p l e t e . V e r i f i c a t i o n   4 2 %   c o m p l e t e . V e r i f i c a t i o n   4 2 %   c o
m p l e t e . V e r i f i c a t i o n   4 3 %   c o m p l e t e . V e r i f i c a t i o n   4 3 %   c o m p l e t e . V e r i f i c a t i o n   4 3 %   c o m p l e t
e . V e r i f i c a t i o n   4 4 %   c o m p l e t e . V e r i f i c a t i o n   4 4 %   c o m p l e t e . V e r i f i c a t i o n   4 4 %   c o m p l e t e . V e r
i f i c a t i o n   4 5 %   c o m p l e t e . V e r i f i c a t i o n   4 5 %   c o m p l e t e . V e r i f i c a t i o n   4 6 %   c o m p l e t e . V e r i f i c a
t i o n   4 6 %   c o m p l e t e . V e r i f i c a t i o n   4 6 %   c o m p l e t e . V e r i f i c a t i o n   4 7 %   c o m p l e t e . V e r i f i c a t i o n
4 7 %   c o m p l e t e . V e r i f i c a t i o n   4 7 %   c o m p l e t e . V e r i f i c a t i o n   4 8 %   c o m p l e t e . V e r i f i c a t i o n   4 8 %   c
o m p l e t e . V e r i f i c a t i o n   4 9 %   c o m p l e t e . V e r i f i c a t i o n   4 9 %   c o m p l e t e . V e r i f i c a t i o n   4 9 %   c o m p l e
t e . V e r i f i c a t i o n   5 0 %   c o m p l e t e . V e r i f i c a t i o n   5 0 %   c o m p l e t e . V e r i f i c a t i o n   5 0 %   c o m p l e t e . V e
r i f i c a t i o n   5 1 %   c o m p l e t e . V e r i f i c a t i o n   5 1 %   c o m p l e t e . V e r i f i c a t i o n   5 2 %   c o m p l e t e . V e r i f i c
a t i o n   5 2 %   c o m p l e t e . V e r i f i c a t i o n   5 2 %   c o m p l e t e . V e r i f i c a t i o n   5 3 %   c o m p l e t e . V e r i f i c a t i o n
  5 3 %   c o m p l e t e . V e r i f i c a t i o n   5 3 %   c o m p l e t e . V e r i f i c a t i o n   5 4 %   c o m p l e t e . V e r i f i c a t i o n   5 4 %
c o m p l e t e . V e r i f i c a t i o n   5 5 %   c o m p l e t e . V e r i f i c a t i o n   5 5 %   c o m p l e t e . V e r i f i c a t i o n   5 5 %   c o m p l
e t e . V e r i f i c a t i o n   5 6 %   c o m p l e t e . V e r i f i c a t i o n   5 6 %   c o m p l e t e . V e r i f i c a t i o n   5 6 %   c o m p l e t e . V
e r i f i c a t i o n   5 7 %   c o m p l e t e . V e r i f i c a t i o n   5 7 %   c o m p l e t e . V e r i f i c a t i o n   5 8 %   c o m p l e t e . V e r i f i
c a t i o n   5 8 %   c o m p l e t e . V e r i f i c a t i o n   5 8 %   c o m p l e t e . V e r i f i c a t i o n   5 9 %   c o m p l e t e . V e r i f i c a t i o
n   5 9 %   c o m p l e t e . V e r i f i c a t i o n   6 0 %   c o m p l e t e . V e r i f i c a t i o n   6 0 %   c o m p l e t e . V e r i f i c a t i o n   6 0 %
  c o m p l e t e . V e r i f i c a t i o n   6 1 %   c o m p l e t e . V e r i f i c a t i o n   6 1 %   c o m p l e t e . V e r i f i c a t i o n   6 1 %   c o m p
l e t e . V e r i f i c a t i o n   6 2 %   c o m p l e t e . V e r i f i c a t i o n   6 2 %   c o m p l e t e . V e r i f i c a t i o n   6 3 %   c o m p l e t e .
V e r i f i c a t i o n   6 3 %   c o m p l e t e . V e r i f i c a t i o n   6 3 %   c o m p l e t e . V e r i f i c a t i o n   6 4 %   c o m p l e t e . V e r i f
i c a t i o n   6 4 %   c o m p l e t e . V e r i f i c a t i o n   6 4 %   c o m p l e t e . V e r i f i c a t i o n   6 5 %   c o m p l e t e . V e r i f i c a t i
o n   6 5 %   c o m p l e t e . V e r i f i c a t i o n   6 6 %   c o m p l e t e . V e r i f i c a t i o n   6 6 %   c o m p l e t e . V e r i f i c a t i o n   6 6
%   c o m p l e t e . V e r i f i c a t i o n   6 7 %   c o m p l e t e . V e r i f i c a t i o n   6 7 %   c o m p l e t e . V e r i f i c a t i o n   6 7 %   c o m
p l e t e . V e r i f i c a t i o n   6 8 %   c o m p l e t e . V e r i f i c a t i o n   6 8 %   c o m p l e t e . V e r i f i c a t i o n   6 9 %   c o m p l e t e
. V e r i f i c a t i o n   6 9 %   c o m p l e t e . V e r i f i c a t i o n   6 9 %   c o m p l e t e . V e r i f i c a t i o n   7 0 %   c o m p l e t e . V e r i
f i c a t i o n   7 0 %   c o m p l e t e . V e r i f i c a t i o n   7 0 %   c o m p l e t e . V e r i f i c a t i o n   7 1 %   c o m p l e t e . V e r i f i c a t
i o n   7 1 %   c o m p l e t e . V e r i f i c a t i o n   7 2 %   c o m p l e t e . V e r i f i c a t i o n   7 2 %   c o m p l e t e . V e r i f i c a t i o n   7
2 %   c o m p l e t e . V e r i f i c a t i o n   7 3 %   c o m p l e t e . V e r i f i c a t i o n   7 3 %   c o m p l e t e . V e r i f i c a t i o n   7 3 %   c o
m p l e t e . V e r i f i c a t i o n   7 4 %   c o m p l e t e . V e r i f i c a t i o n   7 4 %   c o m p l e t e . V e r i f i c a t i o n   7 5 %   c o m p l e t
e . V e r i f i c a t i o n   7 5 %   c o m p l e t e . V e r i f i c a t i o n   7 5 %   c o m p l e t e . V e r i f i c a t i o n   7 6 %   c o m p l e t e . V e r
i f i c a t i o n   7 6 %   c o m p l e t e . V e r i f i c a t i o n   7 7 %   c o m p l e t e . V e r i f i c a t i o n   7 7 %   c o m p l e t e . V e r i f i c a
t i o n   7 7 %   c o m p l e t e . V e r i f i c a t i o n   7 8 %   c o m p l e t e . V e r i f i c a t i o n   7 8 %   c o m p l e t e . V e r i f i c a t i o n
7 8 %   c o m p l e t e . V e r i f i c a t i o n   7 9 %   c o m p l e t e . V e r i f i c a t i o n   7 9 %   c o m p l e t e . V e r i f i c a t i o n   8 0 %   c
o m p l e t e . V e r i f i c a t i o n   8 0 %   c o m p l e t e . V e r i f i c a t i o n   8 0 %   c o m p l e t e . V e r i f i c a t i o n   8 1 %   c o m p l e
t e . V e r i f i c a t i o n   8 1 %   c o m p l e t e . V e r i f i c a t i o n   8 1 %   c o m p l e t e . V e r i f i c a t i o n   8 2 %   c o m p l e t e . V e
r i f i c a t i o n   8 2 %   c o m p l e t e . V e r i f i c a t i o n   8 3 %   c o m p l e t e . V e r i f i c a t i o n   8 3 %   c o m p l e t e . V e r i f i c
a t i o n   8 3 %   c o m p l e t e . V e r i f i c a t i o n   8 4 %   c o m p l e t e . V e r i f i c a t i o n   8 4 %   c o m p l e t e . V e r i f i c a t i o n
  8 4 %   c o m p l e t e . V e r i f i c a t i o n   8 5 %   c o m p l e t e . V e r i f i c a t i o n   8 5 %   c o m p l e t e . V e r i f i c a t i o n   8 6 %
c o m p l e t e . V e r i f i c a t i o n   8 6 %   c o m p l e t e . V e r i f i c a t i o n   8 6 %   c o m p l e t e . V e r i f i c a t i o n   8 7 %   c o m p l
e t e . V e r i f i c a t i o n   8 7 %   c o m p l e t e . V e r i f i c a t i o n   8 7 %   c o m p l e t e . V e r i f i c a t i o n   8 8 %   c o m p l e t e . V
e r i f i c a t i o n   8 8 %   c o m p l e t e . V e r i f i c a t i o n   8 9 %   c o m p l e t e . V e r i f i c a t i o n   8 9 %   c o m p l e t e . V e r i f i
c a t i o n   8 9 %   c o m p l e t e . V e r i f i c a t i o n   9 0 %   c o m p l e t e . V e r i f i c a t i o n   9 0 %   c o m p l e t e . V e r i f i c a t i o
n   9 0 %   c o m p l e t e . V e r i f i c a t i o n   9 1 %   c o m p l e t e . V e r i f i c a t i o n   9 1 %   c o m p l e t e . V e r i f i c a t i o n   9 2 %
  c o m p l e t e . V e r i f i c a t i o n   9 2 %   c o m p l e t e . V e r i f i c a t i o n   9 2 %   c o m p l e t e . V e r i f i c a t i o n   9 3 %   c o m p
l e t e . V e r i f i c a t i o n   9 3 %   c o m p l e t e . V e r i f i c a t i o n   9 3 %   c o m p l e t e . V e r i f i c a t i o n   9 4 %   c o m p l e t e .
V e r i f i c a t i o n   9 4 %   c o m p l e t e . V e r i f i c a t i o n   9 5 %   c o m p l e t e . V e r i f i c a t i o n   9 5 %   c o m p l e t e . V e r i f
i c a t i o n   9 5 %   c o m p l e t e . V e r i f i c a t i o n   9 6 %   c o m p l e t e . V e r i f i c a t i o n   9 6 %   c o m p l e t e . V e r i f i c a t i
o n   9 7 %   c o m p l e t e . V e r i f i c a t i o n   9 7 %   c o m p l e t e . V e r i f i c a t i o n   9 7 %   c o m p l e t e . V e r i f i c a t i o n   9 8
%   c o m p l e t e . V e r i f i c a t i o n   9 8 %   c o m p l e t e . V e r i f i c a t i o n   9 8 %   c o m p l e t e . V e r i f i c a t i o n   9 9 %   c o m
p l e t e . V e r i f i c a t i o n   9 9 %   c o m p l e t e . V e r i f i c a t i o n   1 0 0 %   c o m p l e t e .


 W i n d o w s   R e s o u r c e   P r o t e c t i o n   d i d   n o t   f i n d   a n y   i n t e g r i t y   v i o l a t i o n s .

PowerShell: Set Service Startup Mode

# setServiceStartupMode.ps1

$computernames=@(
    'TESTWINDOWS001',
    'TESTWINDOWS002'
)
$servicename='TrustedInstaller'
$startupType='Automatic'

foreach ($computername in $computernames){
    Set-Service -computername $computername -Name $servicename -StartupType $startupType
    Get-Service -computername $computername -Name $servicename|start-service
}

Get-Service -computername $computernames -Name $servicename

PowerShell: Move Virtual Machine Storage Using VMM

# moveVmStorageUsingVmm.ps1
# Version 0.01

$vmNames=@(
  'TESTVM0001',  
  'TESTVM0002',
  'TESTVM0003'
)
$storageLocations=@(
  'C:\ClusterStorage\BLOB001',
  'C:\ClusterStorage\BLOB002',
  'C:\ClusterStorage\BLOB003'
)
$storageMaxPercent=75
$confirmation=$true

function moveVmStorageUsingVmm($vmName,$newStorage,$storageMaxPercent=75){  
  try{
    $vmHosts=Get-SCVMHost
    $vm=Get-SCVirtualMachine -Name $vmName
    if($vm.count -eq 1){
      $currentHost=$vm.Hostname
      $storage=Get-SCStorageVolume -VMHost $currentHost|?{$_.Name -eq $newStorage}
      $capacity=$storage.Capacity
      $freespace=$storage.FreeSpace
      $storageUtilizedPercent=[math]::round(($capacity-$freespace)/$capacity*100,2)
      $totalSize=0
      $disks = Get-SCVirtualDiskDrive -VM $vmname
      $disks.VirtualHardDisk.Size|%{$totalSize+=$_}      
      $projectedPercent=[math]::round(($capacity-$freespace+$totalSize)/$capacity*100,2)
      write-host "$newStorage current utilization percentage: $storageUtilizedPercent`% and projected: $projectedPercent`%"
      $storageFeasible=if($projectedPercent -lt $storageMaxPercent){$true}else{$false}
      if($storageFeasible){
        $vmHost=$vmHosts|?{$_.Name -eq $currentHost}
        Move-SCVirtualMachine -VM $vm -VMHost $vmHost -Path $newStorage -UseLAN -UseDiffDiskOptimization # -RunAsynchronously
      }else{
        write-warning "Available storage volume is less than $storageMaxPercent`% and projected: $projectedPercent`%"
        return $false
      }
    }else{
      write-warning "$vmName matches more than 1 guest VM's; hence, this item is skipped."
    }
    return $true
  }catch{
    write-warning $_
    pause
  }
}

$storageIndex=0
$useSameStorage=$true
for($i=0;$i -lt $vmNames.count;$i++){
  $vmName=if($useSameStorage){$vmNames[$i]}else{$vmNames[--$i]}
  $storageLocation=if($useSameStorage){$storageLocations[$storageIndex]}else{$storageLocations[++$storageIndex]}
  if($storageLocation){
    if($confirmation){
      write-host "Move $vmName storage to $storageLocation`?"
      pause
    }else{
      write-host "Moving $vmName storage to $storageLocation ..."
    }
    $useSameStorage=moveVmStorageUsingVmm $vmName $storageLocation $storageMaxPercent 
  }
}

PowerShell: Add Windows NTFS Permissions to File or Folder

The re-usable function:

$path='C:\Windows\servicing'
$accountsToAdd='Administrators'
$permissions='Full'

function addNtfsPermissions ($path,$accountsToAdd,$permissions){
  $acl = Get-ACL $path
  $accessRule=New-Object System.Security.AccessControl.FileSystemAccessRule($accountsToAdd,$permissions,"Allow")
  $acl.AddAccessRule($accessRule)
  Set-Acl $path $acl
  Get-ACL $path
}

addNtfsPermissions $path $accountsToAdd $permissions

Example:

The following is an output of fixing an issue related to ‘TrustedInstaller will not run. Windows Module Installer service missing’ errors.

$computernames=@(
  'TESTWINDOWS1',
  'TESTWINDOWS2'
  )

$path='C:\Windows\servicing'
$accountsToAdd='Administrators'
$permissions='Full'

function addNtfsPermissions ($path,$accountsToAdd,$permissions){
  $acl = Get-ACL $path
  $accessRule=New-Object System.Security.AccessControl.FileSystemAccessRule($accountsToAdd,$permissions,"Allow")
  $acl.AddAccessRule($accessRule)
  Set-Acl $path $acl
  Get-ACL $path
}

foreach($computername in $computernames){
  invoke-command -computername $computername -scriptblock{
    param($addNtfsPermissions,$path,$accountsToAdd,$permissions)
    write-host "Invoking function on $env:computername"
    [scriptblock]::create($addNtfsPermissions).invoke($path,$accountsToAdd,$permissions)
    start-service trustedinstaller
    get-service trustedinstaller
  } -ArgumentList ${function:addNtfsPermissions},$path,$accountsToAdd,$permissions
}
[TESTWINDOWS]: PS C:\Users\kimconnect\Documents> Get-ACL $localPath|select *

PSPath                  : Microsoft.PowerShell.Core\FileSystem::C:\Windows\servicing
PSParentPath            : Microsoft.PowerShell.Core\FileSystem::C:\Windows
PSChildName             : servicing
PSDrive                 : C
PSProvider              : Microsoft.PowerShell.Core\FileSystem
CentralAccessPolicyId   :
CentralAccessPolicyName :
Path                    : Microsoft.PowerShell.Core\FileSystem::C:\Windows\servicing
Owner                   : NT SERVICE\TrustedInstaller
Group                   : NT SERVICE\TrustedInstaller
Access                  : {System.Security.AccessControl.FileSystemAccessRule,
                          System.Security.AccessControl.FileSystemAccessRule,
                          System.Security.AccessControl.FileSystemAccessRule,
                          System.Security.AccessControl.FileSystemAccessRule...}
Sddl                    : O:S-1-5-80-956008885-3418522649-1831038044-1853292631-2271478464G:S-1-5-80-956008885-34185226
                          49-1831038044-1853292631-2271478464D:PAI(A;OICIIO;GXGR;;;SY)(A;;0x1200a9;;;SY)(A;;FA;;;BA)(A;
                          OICIIO;GXGR;;;BA)(A;OICIIO;GXGR;;;BU)(A;;0x1200a9;;;BU)(A;OICIIO;GA;;;S-1-5-80-956008885-3418
                          522649-1831038044-1853292631-2271478464)(A;;FA;;;S-1-5-80-956008885-3418522649-1831038044-185
                          3292631-2271478464)(A;;0x1200a9;;;AC)(A;OICIIO;GXGR;;;AC)(A;;0x1200a9;;;S-1-15-2-2)(A;OICIIO;
                          GXGR;;;S-1-15-2-2)
AccessToString          : NT AUTHORITY\SYSTEM Allow  -1610612736
                          NT AUTHORITY\SYSTEM Allow  ReadAndExecute, Synchronize
                          BUILTIN\Administrators Allow  FullControl
                          BUILTIN\Administrators Allow  -1610612736
                          BUILTIN\Users Allow  -1610612736
                          BUILTIN\Users Allow  ReadAndExecute, Synchronize
                          NT SERVICE\TrustedInstaller Allow  268435456
                          NT SERVICE\TrustedInstaller Allow  FullControl
                          APPLICATION PACKAGE AUTHORITY\ALL APPLICATION PACKAGES Allow  ReadAndExecute, Synchronize
                          APPLICATION PACKAGE AUTHORITY\ALL APPLICATION PACKAGES Allow  -1610612736
                          APPLICATION PACKAGE AUTHORITY\ALL RESTRICTED APPLICATION PACKAGES Allow  ReadAndExecute,
                          Synchronize
                          APPLICATION PACKAGE AUTHORITY\ALL RESTRICTED APPLICATION PACKAGES Allow  -1610612736
AuditToString           :
AccessRightType         : System.Security.AccessControl.FileSystemRights
AccessRuleType          : System.Security.AccessControl.FileSystemAccessRule
AuditRuleType           : System.Security.AccessControl.FileSystemAuditRule
AreAccessRulesProtected : True
AreAuditRulesProtected  : False
AreAccessRulesCanonical : True
AreAuditRulesCanonical  : True

[TESTWINDOWS]: PS C:\Users\kimconnect\Documents> get-service trustedinstaller
Status   Name               DisplayName
------   ----               -----------
Stopped  trustedinstaller   Windows Modules Installer

[TESTWINDOWS]: PS C:\Users\kimconnect\Documents> get-service trustedinstaller|start-service
[TESTWINDOWS]: PS C:\Users\kimconnect\Documents> get-service trustedinstaller
Status   Name               DisplayName
------   ----               -----------
Running  trustedinstaller   Windows Modules Installer

PS C:\Windows\system32> get-service -Name trustedinstaller -ComputerName $computernames|start-service

PS C:\Windows\system32> get-service -Name trustedinstaller -ComputerName $computernames|select MachineName,ServiceName,S
tartType,Status

MachineName     ServiceName      StartType  Status
-----------     -----------      ---------  ------
TESTWINDOWS0001 trustedinstaller    Manual Running
TESTWINDOWS0002 trustedinstaller    Manual Running

Microsoft SQL Server Connection Timeout

Error Message:

Resolution:

a. Check SQL Server’s Query Execution Timeout: SSMS > Login > Tools > Options > Query Execution

b. Test port 1433 (known common default sql port) from client to server

# Quick commands
$servername='sql01'
Test-NetConnection $servername -port 1433
portqry.exe -n $servername -p tcp -e 1433
# Sample output
PS C:\Users\sqladmin> Test-NetConnection $servername -port 1433
ComputerName : sql01
RemoteAddress : x.x.x.x
RemotePort : 1433
InterfaceAlias : Ethernet
SourceAddress : y.y.y.y
TcpTestSucceeded : True

PS C:\Users\sqladmin> portqry.exe -n $servername -p tcp -e 1433
Querying target system called:
sql01
Attempting to resolve name to IP address...
Name resolved to x.x.x.x
querying...
TCP port 1433 (ms-sql-s service): LISTENING

Search for Windows computers in a certain subnet using Active Directory

# Search for Windows computers in a certain subnet using Active Directory
$subnetQuery='10.10'
$filterString='2016'
$computers=Get-ADComputer -Filter "enabled -eq 'true' -and OperatingSystem -like '*$filterString*'"`
-Properties Name,Operatingsystem,OperatingSystemVersion,IPv4Address |
Sort-Object -Property Operatingsystem | Select-Object -Property Name,Operatingsystem,OperatingSystemVersion,IPv4Address
$results=$computers|?{$_.IPv4Address|?{[string]$_ -like "*$subnetQuery*"}}
write-host "$($results.count) computer(s) have been matched.`r`n$results"
# Sample output
Name            Operatingsystem              OperatingSystemVersion IPv4Address
----            ---------------              ---------------------- -----------
SERVER-NAME-001 Windows Server 2016 Standard 10.0 (14393)           10.10.120.9
SERVER-NAME-002 Windows Server 2016 Standard 10.0 (14393)           10.10.120.10
------ Results truncated ---------

Microsoft SQL Server Replication Setup Error Number MSSQL_REPL2110 and Resolution

Symptom:

The distribution agent failed to create temporary files in ‘C:\Program Files\Microsoft SQL Server\130\COM’ directory
The distribution agent failed to create temporary files in 'C:\Program Files\Microsoft SQL Server\130\COM' directory. System returned errorcode 5. (Source: MSSQL_REPL, Error number: MSSQL_REPL21100)
Get help: http://help/MSSQL_REPL21100

Resolution:
– Add ‘NT Service\SQLSERVERAGENT’ account FULL permissions into the ‘C:\Program Files\Microsoft SQL Server\[NNN]\COM’ directory (e.g. ‘C:\Program Files\Microsoft SQL Server\130\COM’)
– Assuming that the default account has been used as the run-as account for the SQL Server Agent service.
– Assuming the referenced account above is assigned to the replication job.
– If the Distribution Agent is invoked from a command line, one must grant write permissions to the COM folder for the account that is used to run the Distribution Agent.

Get Hyper-V Cluster Automatic Balancing Configurations

# Get the configs
$clustername='hqhyv-cluster'
$level=(Get-Cluster $clustername).AutoBalancerLevel
$mode=(Get-Cluster $clustername).AutoBalancerMode
write-host "Current cluster $clusterName AutoBalanceLevel=$level AutoBalanceMode=$mode"

# Legend:
AutoBalancerLevel Behavior
1 (default)	Low	Move when host is more than 80% loaded
2 Medium	Move when host is more than 70% loaded
3 High	Average nodes and move when host is more than 5% above average

AutoBalancerMode Behavior
0 Disabled
1 Load balance on node join
2 (default)	Load balance on node join and every 30 minutes

Intermittent Ping Request Time Out Due to An Outdated ARP Table Entry of a Ubuntu Server

Scenario:

– Server A and Server B hardware are of the same model and capacity
– Server A and Server B hard drives were been swapped recently, where Server A hard drives had been transferred to be installed in Server B and vice versa
– Server A was running Ubuntu Linux, and Server B’s OS was VMWare
– Server A, which had Server B’s VMWare OS was able to boot without any problems
– Server B, which had Server A’s Ubuntu Server OS was able to boot.
– Other servers on the same VLAN were able to connect to Server B without problems
– Users from different VLANs complained that they could not reach Server B using its original Server A’s Ubuntu Linux IP address, even though that IP was statically configured on Server A prior to the hard drive switching incident
– Ping results to Server B were intermittent successes and failures

From 10.10.140.128 icmp_seq=760 Destination Host Unreachable
From 10.10.140.128 icmp_seq=761 Destination Host Unreachable
From 10.10.140.128 icmp_seq=762 Destination Host Unreachable
64 bytes from 10.10.100.228: icmp_seq=1 ttl=64 time=1.199 ms
From 10.10.140.128 icmp_seq=760 Destination Host Unreachable
From 10.10.140.128 icmp_seq=761 Destination Host Unreachable
From 10.10.140.128 icmp_seq=762 Destination Host Unreachable
From 10.10.140.128 icmp_seq=762 Destination Host Unreachable
64 bytes from 10.10.100.228: icmp_seq=1 ttl=64 time=1.199 ms
Troubleshooting:

– On clients with issues connecting to the server, run the ‘arp -a’ command to discover the MAC address associated with the server’s ip
– It appeared that the MAC address for the original server A’s IP, which now resided in Server B’s chassis, pointed to Server B mac address.
– It was also confirmed on Server B by running either ‘ifconfig’ or ‘ip addr show’

testuser@ubuntu-server:~$ ifconfig
eno1: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
inet 10.10.100.228 netmask 255.255.255.0 broadcast 192.168.100.255
ether 72:c8:fb:5e:1d:eb txqueuelen 1000 (Ethernet)
RX packets 543498 bytes 634630257 (634.6 MB)
RX errors 0 dropped 5 overruns 0 frame 0
TX packets 118913 bytes 17683157 (17.6 MB)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
device interrupt 16 memory 0xb8a00000-b8a20000
testuser@ubuntu-server:/home/kim# ip addr show
2: eno1: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP group default qlen 1000
link/ether 72:c8:fb:5e:1d:eb brd ff:ff:ff:ff:ff:ff
inet 10.10.100.228/24 brd 192.168.100.255 scope global dynamic noprefixroute eno1
valid_lft 85514sec preferred_lft 85514sec
Resolution:

Whenever a Ubuntu Server hard drive has been moved to a different server, one must also reconfigure its MAC address to reflect its new host’s network interface.

Here’s the instruction via GUI: click on the network icon > select Edit connections > Select your current network > Edit the selected connection > select the Ethernet tab > set Clone Mac address = {input the desired MAC address}, stable, or Permanent > Disconnect > re-connect the interface

CLI method:

# Edit the interfaces file
sudo vim /etc/network/interfaces
# add this entry for the eth0 interface
iface eth0 inet static
hwaddress ether 00:00:00:00:MAC-ADDRESS-HERE
# restart server
sudo reboot now

Optional: the intermediary routers and switches should automatically update its ARP table with the changes so that clients could be redirected to the desired and correct Server. Here are some commands to flush the ARP table on switch or router running a Linux based OS:

# flush Mac Table of a Linux based router/switch
admin@test-switch:~$ sudo ip -s -s neigh flush all
[sudo] password for kim:
10.10.100.100 dev eno1 used 1420/1495/1417 probes 6 FAILED
10.10.100.50 dev eno1 lladdr 00:0c:29:27:3b:13 used 2599/2159/2099 probes 6 STALE
10.10.100.2 dev eno1 used 1026/1338/1023 probes 6 FAILED
10.10.100.1 dev eno1 lladdr 74:83:c2:df:f9:8b ref 1 used 2617/0/2617 probes 4 REACHABLE
10.10.100.11 dev eno1 used 971/2677/969 probes 6 FAILED
10.10.100.5 dev eno1 lladdr 00:11:32:e4:c5:ca used 137/132/108 probes 1 STALE

*** Round 1, deleting 6 entries ***
*** Flush is complete after 1 round ***

PowerShell: Create Hyper-V Guest VM From Virtual Disk (VHDX)

Part 1: Creating Hyper-V Guest VM From a Virtual Disk

# createHyperVGuestVmFromDisk.ps1
# Version 0.02
# The intent of this script is to create a Hyper-V Guest VM basing on existing backup VHDX file(s)

$sourceVhdx='\\FILESERVER008\_Images\Windows2019_Image.vhdx'
$destinationFolder='\\VIRTUALMACHINES\STAGE'
$network='External-Connection'
$vlan='3000'

$newVmName='TESTVM009'
$memory='8GB'
$cpus=4
$secureBoot=$true # Windows: True, Linux: False
$extraDisks=@($null) # $extraDisks=@('test')
$generation=2
$deleteSourceDisks=$true
$onlineVm=$true

function createHyperVGuestVmFromDisk{
  param(
      $sourceVhdx,
      $newVmName,
      $destinationFolder,
      $memory='4GB',
      $cpus=2,
      $network,
      $vlan,
      $extraDisks=$null,
      $generation=2,
      $secureBoot=$false,
      $onlineVm=$true,
      $deleteSourceDisks=$false
  )
  $ErrorActionPreference = 'stop'
  
  function confirmation($content,$testValue="I confirm",$maxAttempts=3){
    $confirmed=$false
    $cancelCondition=@('cancel','no','exit','nope')
    $attempts=0
    clear-host 
    write-host $($content|out-string).trim()
    write-host "`r`nPlease review this content for accuracy.`r`n"
    while ($attempts -le $maxAttempts){
        if($attempts++ -ge $maxAttempts){
            write-host "A maximum number of attempts have reached. No confirmations received!`r`n"
            break;
            }
        $userInput = Read-Host -Prompt "Please type in this value => $testValue <= to confirm. Input CANCEL to skip this item";
        if ($userInput.ToLower() -eq $testValue.ToLower()){
            $confirmed=$true;
            write-host "Confirmed!`r`n";
            break;                
        }elseif($userInput.tolower() -in $cancelCondition){
            write-host 'Cancel command received.'
            $confirmed=$false
            break
        }else{
            clear-host
            $content|write-host
            write-host "Attempt number $attempts of $maxAttempts`: $userInput does not match $testValue. Try again or Input CANCEL to skip this item`r`n"
            }
        }
    return $confirmed
  }

  try{
      $newFolder="$destinationFolder\$newVmName"
      if(!(test-path $newFolder)){new-item -ItemType Directory -Path $newFolder -force}              
      $newVhdx="$newFolder\$newVmName`_disk0.vhdx"
      if(!(test-path $newVhdx)){
          New-Item -ItemType File -Path $newVhdx -Force # touch before copying contents
          Copy-Item -Path $sourceVhdx -Destination $newVhdx
      }else{
          write-warning "Volume $newVhdx already exists. Thus, that VMDK will be used instead of a clone."
      }
      New-VM -Name $newVmName `
              -MemoryStartupBytes $($memory/1) `
              -BootDevice VHD `
              -VHDPath $newVhdx `
              -Path $newFolder `
              -Generation $generation `
              -Switch $network         
      if($vlan){Set-VMNetworkAdapterVlan -VMName $newVmName -Access -VlanId $vlan}
              if($cpus -gt 1){Set-VMProcessor $newVmName -Count $cpus}
      Set-VMProcessor $newVmName -CompatibilityForMigrationEnabled $true
      if(!$secureBoot){Set-VMFirmware -VMName $newVmName -DisableSecureBoot}
      # Adding disks (optional)
      if($extraDisks){
          for($i=0;$i -lt $extraDisks.count;$i++){
            $extraDisk=$extraDisks[$i]
            $isvalidDisk=if(test-path $extraDisk){$extraDisk}else{$null}
            if($isvalidDisk){
              $newDiskPath=(join-path $destinationFolder $vmName) + "\$vmName`_disk$($i+1).vmdk"
              if(!(test-path $newDiskPath)){
                New-Item -ItemType File -Path $newDiskPath -Force # touch before copying contents
                Copy-Item -Path $extraDisk -Destination $newDiskPath
              }else{
                  write-warning "Volume $newDiskPath already exists. Thus, that VMDK will be used instead of a copy."
              }              
              Add-VMHardDiskDrive -VMName $newVmName -Path $newDiskPath 
            }else{
              write-warning "Disk path '$extraDisk' in invalid."
            }
          }
      }else{
        write-host "$newVmName has no extra disks to attach."
      }
      $disksToRemove=[array]$extraDisks+$sourceVhdx|?{$_} # join string to array and remove empty entries
      foreach($diskToRemove in $disksToRemove){
        $confirmed=confirmation "Remove source disk $diskToRemove"
        if($confirmed){
          remove-item $diskToRemove -force
        }else{
          write-host "$diskToRemove NOT removed."
        }
      }
      if($onlineVm){
          start-vm $newVmName
      }
      return $true
  }catch{
      write-warning "$($error[0])"
      return $false
  }
}

createHyperVGuestVmFromDisk $sourceVhdx `
  $newVmName `
  $destinationFolder `
  $memory `
  $cpus `
  $network `
  $vlan `
  $extraDisks `
  $generation `
  $secureBoot `
  $onlineVm `
  $deleteSourceDisk

Part 2: Adding New VM to Cluster

function addVmToCluster{
    param($vmNames,$targetCluster)
    $results=@()
    foreach ($vmName in $vmNames){
        try{
            #Start-VM -Name $vmName -EA Stop
            if(!$targetCluster){$targetCluster=(get-cluster -ea SilentlyContinue).Name}
            if($targetCluster){
                $null=Add-ClusterVirtualMachineRole -Cluster $targetCluster -VirtualMachine $vmName -EA Stop
                $results+=[hashtable]@{$vmName=$true}
            }else{
                write-host "No clusters defined."
                $results+=[hashtable]@{$vmName=$false}
                }
            $moved=if(get-cluster -ea SilentlyContinue){Move-ClusterVirtualMachineRole $newVmName}else{$false}
            if($moved){write-host "'$newVmname' has been moved to $($moved.OwnerNode)"}
        }catch{
            write-warning "$($error[0])"
            $results+=[hashtable]@{$vmName=$false}
            }
    }
    return $results
}

addVmToCluster $newVmName

Possible Error Message:

Microsoft Hyper-V UEFI

Virtual Machine Boot Summary

1.SCSI Disk (0,0) the boot loader did not load an operating system
2. Network adapter (00155D406142) a boot image was not found

No operating system was loaded. Your virtual machine may be configured incorrectly. Exit and rec-configure your VM or click restart to retry the current boot sequence again.

Resolution:

The case where this error has been thrown has been associated with an incorrect virtual machine generation type. Hence, the resolution has been:

A. Convert Generation 2 machine type back to Generation 1 as the original source disk VM must match its re-creation.
B. The misconfigured VM must be ‘deleted’ and re-created as a Generation 1 VM.

# Converting Generation 2 virtual disk to Gen 1
$diskFile='\\VIRTUALMACHINES\HyperV\originalDisk_gen2.vhdx'
$fixedFile='\\VIRTUALMACHINES\HyperV\originalDisk_gen1.vhdx'
Convert-VHD -Path $diskFile -DestinationPath $fixedFile -VHDType Dynamic

PowerShell: Find Guest VMs Associated with a Certain Storage Path

# findGuestMvsByStorage.ps1

$storagePath='\\SMBSERVER009'

function getAllGuestVms($clusterName){
  try{
    Import-Module FailoverClusters
    $clusterName=if($clusterName){
      $clustername
    }else{
      (get-cluster).name
    }
    $allHyperVHosts={(Get-ClusterNode -Cluster $clusterName|?{ $_.State -eq "Up" }).Name | %{$_.ToLower()}}.Invoke()
    $allVms=foreach ($hyperVHost in $allHyperVHosts){
      invoke-command -computername $hyperVHost -scriptblock{
        write-host "Getting VM List on $env:computername";
        Get-VM |select-object Name,State,Status,Path
      }|select-object * -ExcludeProperty RunspaceId,PSShowComputerName
    }
    if($allVms){return $allVms}else{return $null}
  }catch{
    write-warning $_
    return $false
  }
}
function findGuestMvsByStorage{
  param (
    $storagePath,
    $clusterName=$null
    )
  try{
      $allVms=getAllGuestVms $clusterName
      if(!$allVms){return $null}
      $matchedStorage=$allVms|?{$_.Path -like "*$storagePath*"}
      $online=$matchedStorage|?{$_.State.Value -like 'Running*'}
      $offline=$matchedStorage|?{$_.State.Value -notlike 'Running*'}
      if($online){
        write-host "There are $($online.count) online VMs associated with '$storagePath'"
      }
      if($offline){
        write-host "There are $($offline.count) offlined VMs associated with '$storagePath'"
      }
      if($matchedStorage){
        $matchedStorage
        return $matchedStorage
      }else{
        write-host "'$storagePath' is not being associated with any VM in cluster '$((get-cluster).Name)'"
        return $null
      }
  }catch{
      write-warning $_
      return $false
  }
}

$result=findGuestMvsByStorage $storagePath
$result|select Name,State,PSComputerName
# Sample Output
PS C:\Windows\system32> $result=findGuestMvsByStorage $storagePath
Getting VM List on HYV01
Getting VM List on HYV02
Getting VM List on HYV03
Getting VM List on HYV04
Getting VM List on HYV05
Getting VM List on HYV06
Getting VM List on HYV07
Getting VM List on HYV08
Getting VM List on HYV09
Getting VM List on HYV10
Getting VM List on HYV11
Getting VM List on HYV12
Getting VM List on HYV13
Getting VM List on HYV14
Getting VM List on HYV15
Getting VM List on HYV16
Getting VM List on HYV17
Getting VM List on HYV18
Getting VM List on HYV19
There are 6 online VMs associated with '\\FILESERVER009'
There are 16 offlined VMs associated with '\\FILESERVER009'

PS C:\Windows\system32> $result|select Name,State
Name                           State
----                           -----
TESTVM01                       OffCritical
TESTVM02                       Off
TESTVM03                       OffCritical
TESTVM04                       OffCritical
TESTVM05                       RunningCritical

PowerShell: Restart a Service on All Hyper-V Hosts of a Cluster

$serviceName='vmms'
$clusterName='HyperV-cluster001'

function restartServiceAllClusterNodes($service='vmms',$clusterName){
  function restartService($serviceName){
    $waitSeconds=40
    $isValidProcess=try{[bool](get-service $serviceName -EA Stop)}catch{$false}
    if($isValidProcess){
        try{
            $process=Start-Process -FilePath powershell.exe -ArgumentList "-Command Restart-Service $serviceName" -PassThru -NoNewWindow
            $process|Wait-Process -Timeout $waitSeconds -ErrorAction Stop
            return $true
        }catch{
            write-warning $_
            $process|Stop-Process -Force
            $processId=(get-process $serviceName).Id
            if($processId){
                write-host "Program now forcefully kills PID $processId of process $serviceName"
                $null=$processId|%{taskkill /f /pid $_} # works more reliably than Stop-Process $processName -Force
                Start-Service $serviceName -ErrorAction Ignore
                $started=$(try{get-service $serviceName}catch{$false})
                if($started){
                    write-host "'serviceName' status is now $($started.Status)"
                    return $true
                }else{
                    write-warning "'serviceName' status is $($started.Status)"
                    return $false
                }
            }else{
                write-warning "Service '$serviceName' PID not found."
                return $false        
            }
        }
    }
  }

  $results=@()
  try{
    Import-Module FailoverClusters
    $clusterName=if($clusterName){
      invoke-command -computername $clustername {(get-cluster).name}
    }else{
      (get-cluster).name
    }
    $allHyperVHosts={(Get-ClusterNode -Cluster $clusterName|?{ $_.State -eq "Up" }).Name | %{$_.ToLower()}}.Invoke()
    foreach ($hyperVHost in $allHyperVHosts){
      $result=invoke-command -computername $hyperVHost -EA SilentlyContinue -scriptblock {
        param($restartService,$serviceName)
        [scriptblock]::create($restartService).invoke($servicename)
      } -Args ${function:restartService},$serviceName
      write-host "$hypervHost=$result"
      $results+=[pscustomobject]@{$hypervHost=$result}
    }
  }catch{
    write-warning $_    
  }
}

$results=restartServiceAllClusterNodes $serviceName $clusterName
$results

PowerShell: Find Hyper-V Host by Guest VM Name

# findVmHostByGuestName.ps1

$vmName='TESTVM'

function findVmHostByGuestName($vmName){
    try{
        Import-Module Hyper-V
        Import-Module FailoverClusters
        $allHyperVHosts={(Get-ClusterNode | Where { $_.State -eq "Up" }).Name | %{$_.ToLower()}}.Invoke()
        $allVms=foreach ($hyperVHost in $allHyperVHosts){invoke-command -computername $hyperVHost -scriptblock{write-host "Getting VM List on $env:computername";Get-VM |select Name,Path}|select-object * -ExcludeProperty RunspaceId,PSShowComputerName}
        $matchedHost=$allVms|?{$_.Name -like "*$vmName*"}
        if($matchedHost){
            return $matchedHost
        }else{
            write-host "'$vmName' is not found in cluster '$((get-cluster).Name)'"
            return $null
        }
    }catch{
        write-warning $_
        return $false
    }
}

findVmHostByGuestName $vmName

PowerShell: Get All Hyper-V Host Spectre Patch Versions

# getAllVmSpectrePatchVersions.ps1

function getHyperVHostsInForest{
    function includeRSAT{
        $ErrorActionPreference='stop'
        [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
        #$rsatWindows7x32='https://download.microsoft.com/download/4/F/7/4F71806A-1C56-4EF2-9B4F-9870C4CFD2EE/Windows6.1-KB958830-x86-RefreshPkg.msu'
        $rsatWindows7x64='https://download.microsoft.com/download/4/F/7/4F71806A-1C56-4EF2-9B4F-9870C4CFD2EE/Windows6.1-KB958830-x64-RefreshPkg.msu'
        $rsatWindows81='https://download.microsoft.com/download/1/8/E/18EA4843-C596-4542-9236-DE46F780806E/Windows8.1-KB2693643-x64.msu'
        $rsat1709 = "https://download.microsoft.com/download/1/D/8/1D8B5022-5477-4B9A-8104-6A71FF9D98AB/WindowsTH-RSAT_WS_1709-x64.msu"
        $rsat1803 = "https://download.microsoft.com/download/1/D/8/1D8B5022-5477-4B9A-8104-6A71FF9D98AB/WindowsTH-RSAT_WS_1803-x64.msu"
        $rsatWs2016 = "https://download.microsoft.com/download/1/D/8/1D8B5022-5477-4B9A-8104-6A71FF9D98AB/WindowsTH-RSAT_WS2016-x64.msu"
   
        # This command does not work on Windows 2012R2
        #$releaseId=(Get-ItemProperty -Path "HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion" -Name ReleaseId).ReleaseId
        #Get-ItemProperty : Property ReleaseId does not exist at path HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows
        #NT\CurrentVersion.
        #At line:1 char:2
        #+ (Get-ItemProperty -Path "HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion" -Na ...
        #+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
        #    + CategoryInfo          : InvalidArgument: (ReleaseId:String) [Get-ItemProperty], PSArgumentException
        #    + FullyQualifiedErrorId : System.Management.Automation.PSArgumentException,Microsoft.PowerShell.Commands.GetItemPropertyCommand
   
        $releaseId=(Get-Item "HKLM:SOFTWARE\Microsoft\Windows NT\CurrentVersion").GetValue('ReleaseID')
        $osVersion=[System.Environment]::OSVersion.Version
        [double]$osVersionMajorMinor="$($osVersion.Major).$($osVersion.Minor)" 
        $osName=(Get-WmiObject Win32_OperatingSystem).Name
        #$osType=switch ((Get-CimInstance -ClassName Win32_OperatingSystem).ProductType){
        #    1 {'client'}
        #    2 {'domaincontroller'}
        #    3 {'memberserver'}
        #    }
   
        $windowsVersion=(Get-CimInstance Win32_OperatingSystem).Version
   
        switch ($releaseId){
            1607{write-host 'Windows Server 2016 Release 1607 detected';$link=$rsatWs2016;break}
            1709{write-host 'Windows Server 2016 Release 1709 detected';$link=$rsat1709;break}
            1803{write-host 'Windows Server 2016 Release 1803 detected';$link=$rsat1803}
        }
       
        switch ($osVersionMajorMinor){
            {$_ -eq 6.0}{write-host 'Windows Server 2008 or Windows Vista detected';$link=$rsat1709;break}
            {$_ -eq 6.1}{write-host 'Windows Server 2008 R2 or Windows 7 detected';$link=$rsatWindows7x64;break}
            {$_ -eq 6.2}{write-host 'Windows Server 2012 or Windows 8.1 detected';$link=$rsatWindows81;break}
            {$_ -eq 6.3}{write-host 'Windows Server 2012 R2 detected';$link=$rsatWindows81}
        }
  
        if (!(Get-Module -ListAvailable -Name ActiveDirectory -EA SilentlyContinue)){
            Write-host "Prerequisite checks: module ActiveDirectory NOT currently available on this system. Please wait while the program adds that plugin..."
            try{
                # If OS is Windows Server, then install RSAT using a different method
                if ($osName -match "^Microsoft Windows Server") {
                    # This sequence has confirmed to be valid on Windows Server 2008 R2 and above
                    Write-Verbose "Importing Windows Feature: RSAT-AD-PowerShell"
                    Import-Module ServerManager
                    Add-WindowsFeature RSAT-AD-PowerShell
                    }
                else{
                    Write-Verbose "This sequence targets Windows Client versions"
                    $destinationFile= ($ENV:USERPROFILE) + "\Downloads\" + (split-path $link -leaf)
                    Write-Host "Downloading RSAT from $link..."
                    Start-BitsTransfer -Source $link -Destination $destinationFile
                    $fileCheck=Get-AuthenticodeSignature $destinationFile
                    if($fileCheck.status -ne "valid") {write-host "$destinationFile is not valid. Please try again...";break}
                    $wusaCommand = $destinationFile + " /quiet"
                    Write-host "Installing RSAT - please wait..."
                    Start-Process -FilePath "C:\Windows\System32\wusa.exe" -ArgumentList $wusaCommand -Wait
                    }
                return $true
                }
            catch{
                write-warning "$($error[0].Exception)"
                return $false
                }
        }else{
            Write-host "Prerequisite checks: module ActiveDirectory IS currently available on this system." -ForegroundColor Green
            return $true
            }
    }
     function listAllHyperVNodes($verbose=$true){
        try{
            $timer=[System.Diagnostics.Stopwatch]::StartNew()
            $domains=(Get-ADForest).Name|%{(Get-ADForest -Identity $_).Name}
            foreach ($domain in $domains){
                #[string]$dc=(get-addomaincontroller -DomainName "$domain" -Discover -NextClosestSite).HostName
                write-host "Collecting all Hyper-V Clusters in $domain. This may take a while, depending on cluster sizes."
                $allClusters=(get-cluster -domain $domain).Name
                if($verbose){
                    $elapsed=[math]::round($timer.Elapsed.TotalMinutes,2)
                    write-host "Minutes elapsed $elapsed`: cluster names collected"
                    }

                $allHyperVNodes=@()
                foreach ($cluster in $allClusters){
                    $nodes=.{$x=Get-ClusterNode -Cluster $cluster -ea SilentlyContinue
                            if($x){
                                $x|Where-Object{$_.State -eq 'Up'}|Select-Object Name,@{name='Cluster';e={$cluster}}
                            }else{
                                $false
                            }
                            }
                    if($nodes){$allHyperVNodes+=$nodes}
                }
                if($verbose){
                    $elapsed=[math]::round($timer.Elapsed.TotalMinutes,2)
                    write-host "Minutes elapsed $elapsed`: Hyper Node names collected..."
                    }
                }                
            return $allHyperVNodes
        }catch{
            Write-Error $_
            return $false
            }
    }
 
    try{
        $null=includeRSAT;
        $hyperVHosts=listAllHyperVNodes
        #$hyperVHostNames=sortArrayStringAsNumbers $hyperVHosts
        $hyperVHostNames=$hyperVHosts|sort -property Cluster
        return $hyperVHostNames
    }catch{
        Write-Error $_
        return $false
        }
    }

function pickList($list){
    # Although it's more efficient to obtain the index and set it as display,
    # humans prefer see a list that starts with 1, instead of 0
    $display=for ($i=0;$i -lt $list.count;$i++){
        "$($i+1)`:`t$($list[$i])`r`n";
        }
    $lines=($display | Measure-Object -Line).Lines
    write-host $($display)
    $maxAttempts=3
    $attempts=0;
    while ($attempts -le $maxAttempts){
        if($attempts++ -ge $maxAttempts){
            write-host "Attempt number $maxAttempts of $maxAttempts. Exiting loop..`r`n"
            break;
            }
        $userInput = Read-Host -Prompt 'Please pick a number from the list above';
        try {
            $value=[int]$userInput;
            }catch{
                $value=-1;
                }
        if ($value -lt 1 -OR $value -gt $lines){
            cls;
            write-host "Attempt number $attempts of $maxAttempts`: $userInput is an invalid value. Try again..`r`n"
            write-host $display
            }else{
                $item=$list[$value-1];
                write-host "$userInput corresponds to $item`r`n";
                return $item
                }
        }     
    }
function selectCluster($clusters){
    # Requires function named pickList
    $uniqueClusters=$clusters|select -unique
    $pickedCluster=$(pickList $uniqueClusters)
    if($pickedCluster){
        return $pickedCluster
    }else{
        write-warning 'No clusternames were picked.'
        return $false
    }
}

function pickHost($hosts){
    # Requires function named pickList
    $pickedHost=$(pickList $hosts)
    if($pickedHost){
        return $pickedHost
    }else{
        write-warning 'No clusternames were picked.'
        return $false
    }
}
function sortArrayStringAsNumbers([string[]]$names){
    $hashTable=@{}
    foreach ($name in $names){
        #[int]$x=.{[void]($name -match '(?:.(\d+))+$');$matches[1]}
        #$x=.{[void]($name -match '(?:.(\d+)+)$');@($name.substring(0,$name.length-$matches[1].length),$matches[1])}
        $x=.{[void]($name -match '(?:.(\d+)+)$');($name.substring(0,$name.length-$matches[1].length))+$matches[1].PadLeft(8,'0')}
        $hashTable.Add($name,$x)
        }
    $sorted=foreach($item in $hashTable.GetEnumerator() | Sort Value){$item.Name}
    return $sorted
}

write-host "Obtaining cluster names and associated hosts..."
$hyperVHostsInForest=getHyperVHostsInForest
$pickedCluster=selectCluster $hyperVHostsInForest.Cluster
$pickedHosts=$hyperVHostsInForest|?{$_.Cluster -eq $pickedCluster}
$pickedHyperVHosts=sortArrayStringAsNumbers $pickedHosts.Name

function getSpectrePatchingVersions($hyperVHosts){
    write-host "Now obtaining Spectre Patching versions of Hyper-V Hosts..."
    $results=@{}
    foreach ($hyperVHost in $hyperVHosts){
        $spectrePatchingVersion=(Get-WmiObject -ComputerName $hyperVHost -ClassName Win32_BIOS).SMBIOSBIOSVersion
        write-host "$hyperVHost`: $spectrePatchingVersion"
        $results+=@{$hyperVHost=$spectrePatchingVersion}
    }
    return $results
}
getSpectrePatchingVersions $pickedHyperVHosts
function setVmMigrationPerformanceRemote($hyperVHosts){
    function setVmMigrationPerformance{
        param($performanceOption='TCPIP') # TCP is most compatible, and the other options are SMB and Compression
        $ErrorActionPreference='stop'
        try{
            Set-VMHost -VirtualMachineMigrationPerformanceOption $performanceOption
            return $true
        }catch{
            return $false
        }
    }
    $results=@{}
    $performanceOption='TCPIP'
    foreach ($hyperVHost in $hyperVHosts){
        try{
            $result=invoke-command -ComputerName $hyperVHost -ScriptBlock {
                param($setVmMigrationPerformance,$performanceOption)
                [scriptblock]::create($setVmMigrationPerformance).invoke($performanceOption)
            } -Args ${function:setVmMigrationPerformance},$performanceOption
            if($result){
                write-host "$hyperVHost`: $performanceOption"
                $results+=@{$hyperVHost=$performanceOption}
            }
        }catch{
            write-warning $_
        }
    }
    return $results
}
setVmMigrationPerformanceRemote $pickedHyperVHosts

PowerShell: Fix All VMs CPU Compatibility Setting

# fixAllVmCpuCompatibility.ps1
# version 0.01
function getHyperVHostsInForest{
    function includeRSAT{
        $ErrorActionPreference='stop'
        [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
        #$rsatWindows7x32='https://download.microsoft.com/download/4/F/7/4F71806A-1C56-4EF2-9B4F-9870C4CFD2EE/Windows6.1-KB958830-x86-RefreshPkg.msu'
        $rsatWindows7x64='https://download.microsoft.com/download/4/F/7/4F71806A-1C56-4EF2-9B4F-9870C4CFD2EE/Windows6.1-KB958830-x64-RefreshPkg.msu'
        $rsatWindows81='https://download.microsoft.com/download/1/8/E/18EA4843-C596-4542-9236-DE46F780806E/Windows8.1-KB2693643-x64.msu'
        $rsat1709 = "https://download.microsoft.com/download/1/D/8/1D8B5022-5477-4B9A-8104-6A71FF9D98AB/WindowsTH-RSAT_WS_1709-x64.msu"
        $rsat1803 = "https://download.microsoft.com/download/1/D/8/1D8B5022-5477-4B9A-8104-6A71FF9D98AB/WindowsTH-RSAT_WS_1803-x64.msu"
        $rsatWs2016 = "https://download.microsoft.com/download/1/D/8/1D8B5022-5477-4B9A-8104-6A71FF9D98AB/WindowsTH-RSAT_WS2016-x64.msu"
   
        # This command does not work on Windows 2012R2
        #$releaseId=(Get-ItemProperty -Path "HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion" -Name ReleaseId).ReleaseId
        #Get-ItemProperty : Property ReleaseId does not exist at path HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows
        #NT\CurrentVersion.
        #At line:1 char:2
        #+ (Get-ItemProperty -Path "HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion" -Na ...
        #+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
        #    + CategoryInfo          : InvalidArgument: (ReleaseId:String) [Get-ItemProperty], PSArgumentException
        #    + FullyQualifiedErrorId : System.Management.Automation.PSArgumentException,Microsoft.PowerShell.Commands.GetItemPropertyCommand
   
        $releaseId=(Get-Item "HKLM:SOFTWARE\Microsoft\Windows NT\CurrentVersion").GetValue('ReleaseID')
        $osVersion=[System.Environment]::OSVersion.Version
        [double]$osVersionMajorMinor="$($osVersion.Major).$($osVersion.Minor)" 
        $osName=(Get-WmiObject Win32_OperatingSystem).Name
        #$osType=switch ((Get-CimInstance -ClassName Win32_OperatingSystem).ProductType){
        #    1 {'client'}
        #    2 {'domaincontroller'}
        #    3 {'memberserver'}
        #    }
   
        $windowsVersion=(Get-CimInstance Win32_OperatingSystem).Version
   
        switch ($releaseId){
            1607{write-host 'Windows Server 2016 Release 1607 detected';$link=$rsatWs2016;break}
            1709{write-host 'Windows Server 2016 Release 1709 detected';$link=$rsat1709;break}
            1803{write-host 'Windows Server 2016 Release 1803 detected';$link=$rsat1803}
        }
       
        switch ($osVersionMajorMinor){
            {$_ -eq 6.0}{write-host 'Windows Server 2008 or Windows Vista detected';$link=$rsat1709;break}
            {$_ -eq 6.1}{write-host 'Windows Server 2008 R2 or Windows 7 detected';$link=$rsatWindows7x64;break}
            {$_ -eq 6.2}{write-host 'Windows Server 2012 or Windows 8.1 detected';$link=$rsatWindows81;break}
            {$_ -eq 6.3}{write-host 'Windows Server 2012 R2 detected';$link=$rsatWindows81}
        }
  
        if (!(Get-Module -ListAvailable -Name ActiveDirectory -EA SilentlyContinue)){
            Write-host "Prerequisite checks: module ActiveDirectory NOT currently available on this system. Please wait while the program adds that plugin..."
            try{
                # If OS is Windows Server, then install RSAT using a different method
                if ($osName -match "^Microsoft Windows Server") {
                    # This sequence has confirmed to be valid on Windows Server 2008 R2 and above
                    Write-Verbose "Importing Windows Feature: RSAT-AD-PowerShell"
                    Import-Module ServerManager
                    Add-WindowsFeature RSAT-AD-PowerShell
                    }
                else{
                    Write-Verbose "This sequence targets Windows Client versions"
                    $destinationFile= ($ENV:USERPROFILE) + "\Downloads\" + (split-path $link -leaf)
                    Write-Host "Downloading RSAT from $link..."
                    Start-BitsTransfer -Source $link -Destination $destinationFile
                    $fileCheck=Get-AuthenticodeSignature $destinationFile
                    if($fileCheck.status -ne "valid") {write-host "$destinationFile is not valid. Please try again...";break}
                    $wusaCommand = $destinationFile + " /quiet"
                    Write-host "Installing RSAT - please wait..."
                    Start-Process -FilePath "C:\Windows\System32\wusa.exe" -ArgumentList $wusaCommand -Wait
                    }
                return $true
                }
            catch{
                write-warning "$($error[0].Exception)"
                return $false
                }
        }else{
            Write-host "Prerequisite checks: module ActiveDirectory IS currently available on this system." -ForegroundColor Green
            return $true
            }
    }
     function listAllHyperVNodes($verbose=$true){
        try{
            $timer=[System.Diagnostics.Stopwatch]::StartNew()
            $domains=(Get-ADForest).Name|%{(Get-ADForest -Identity $_).Name}
            foreach ($domain in $domains){
                #[string]$dc=(get-addomaincontroller -DomainName "$domain" -Discover -NextClosestSite).HostName
                write-host "Collecting all Hyper-V Clusters in $domain. This may take a while, depending on cluster sizes."
                $allClusters=(get-cluster -domain $domain).Name
                if($verbose){
                    $elapsed=[math]::round($timer.Elapsed.TotalMinutes,2)
                    write-host "Minutes elapsed $elapsed`: cluster names collected"
                    }

                $allHyperVNodes=@()
                foreach ($cluster in $allClusters){
                    $nodes=.{$x=Get-ClusterNode -Cluster $cluster -ea SilentlyContinue
                            if($x){
                                $x|Where-Object{$_.State -eq 'Up'}|Select-Object Name,@{name='Cluster';e={$cluster}}
                            }else{
                                $false
                            }
                            }
                    if($nodes){$allHyperVNodes+=$nodes}
                }
                if($verbose){
                    $elapsed=[math]::round($timer.Elapsed.TotalMinutes,2)
                    write-host "Minutes elapsed $elapsed`: Hyper Node names collected..."
                    }
                }                
            return $allHyperVNodes
        }catch{
            Write-Error $_
            return $false
            }
    }
 
    try{
        $null=includeRSAT;
        $hyperVHosts=listAllHyperVNodes
        #$hyperVHostNames=sortArrayStringAsNumbers $hyperVHosts
        $hyperVHostNames=$hyperVHosts|sort -property Cluster
        return $hyperVHostNames
    }catch{
        Write-Error $_
        return $false
        }
    }

function pickList($list){
    # Although it's more efficient to obtain the index and set it as display,
    # humans prefer see a list that starts with 1, instead of 0
    $display=for ($i=0;$i -lt $list.count;$i++){
        "$($i+1)`:`t$($list[$i])`r`n";
        }
    $lines=($display | Measure-Object -Line).Lines
    write-host $($display)
    $maxAttempts=3
    $attempts=0;
    while ($attempts -le $maxAttempts){
        if($attempts++ -ge $maxAttempts){
            write-host "Attempt number $maxAttempts of $maxAttempts. Exiting loop..`r`n"
            break;
            }
        $userInput = Read-Host -Prompt 'Please pick a number from the list above';
        try {
            $value=[int]$userInput;
            }catch{
                $value=-1;
                }
        if ($value -lt 1 -OR $value -gt $lines){
            cls;
            write-host "Attempt number $attempts of $maxAttempts`: $userInput is an invalid value. Try again..`r`n"
            write-host $display
            }else{
                $item=$list[$value-1];
                write-host "$userInput corresponds to $item`r`n";
                return $item
                }
        }     
    }
function selectCluster($clusters){
    # Requires function named pickList
    $uniqueClusters=$clusters|select -unique
    $pickedCluster=$(pickList $uniqueClusters)
    if($pickedCluster){
        return $pickedCluster
    }else{
        write-warning 'No clusternames were picked.'
        return $false
    }
}

function pickHost($hosts){
    # Requires function named pickList
    $pickedHost=$(pickList $hosts)
    if($pickedHost){
        return $pickedHost
    }else{
        write-warning 'No clusternames were picked.'
        return $false
    }
}
function sortArrayStringAsNumbers([string[]]$names){
    $hashTable=@{}
    foreach ($name in $names){
        #[int]$x=.{[void]($name -match '(?:.(\d+))+$');$matches[1]}
        #$x=.{[void]($name -match '(?:.(\d+)+)$');@($name.substring(0,$name.length-$matches[1].length),$matches[1])}
        $x=.{[void]($name -match '(?:.(\d+)+)$');($name.substring(0,$name.length-$matches[1].length))+$matches[1].PadLeft(8,'0')}
        $hashTable.Add($name,$x)
        }
    $sorted=foreach($item in $hashTable.GetEnumerator() | Sort Value){$item.Name}
    return $sorted
}

function enableCpuCompatibility($vmName){
    $compatibilityForMigration=(Get-VMProcessor $vmName).CompatibilityForMigrationEnabled
    if(!$compatibilityForMigration){    
        $vmIsRunning=(get-vm $vmname).State -eq 'Running'
        if($vmIsRunning){stop-vm $vmName}
        Set-VMProcessor $vmName -CompatibilityForMigrationEnabled 1
        if($vmIsRunning){start-vm $vmName}
    }else{
        write-host "$vmName already has CPU CompatibilityForMigrationEnabled set to True"
    }
}

write-host "Obtaining cluster names and associated hosts..."
$hyperVHostsInForest=getHyperVHostsInForest
$pickedCluster=selectCluster $hyperVHostsInForest.Cluster
$pickedHosts=$hyperVHostsInForest|?{$_.Cluster -eq $pickedCluster}
$pickedHyperVHosts=sortArrayStringAsNumbers $pickedHosts.Name
$results=@()
foreach ($hyperVHost in $pickedHyperVHosts){
    write-host "Performing discovery on $hyperVhost..."
    $getVMCpuCompatiblity={
        Get-VMProcessor *|Select-Object VMName,CompatibilityForMigrationEnabled,@{name='Online';e={if((get-vm $_.VMName).State -eq 'Running'){$true}else{$false}}}
    }
    $result=invoke-command -ComputerName $hyperVHost -ScriptBlock $getVMCpuCompatiblity|Select-Object -Property * -ExcludeProperty RunspaceId
    write-host ($result|out-string).trim()
    $results+=$result
}
$negatives=$results|?{$_.CompatibilityForMigrationEnabled -eq $false -and $_.Online -eq $true}

# Fix all items
foreach ($item in $negatives){
    $vmHost=$item.PSComputerName
    $vmName=$item.VMName
    invoke-command -computername $vmHost -scriptblock {
        param($enableCpuCompatibility,$vmName)
        [scriptblock]::create($enableCpuCompatibility).invoke($vmName)
    } -Args ${function:enableCpuCompatibility},$vmName
}
# Fix each item
$vmName='TESTVM008'
$vmHost=($negatives|?{$_.VMName -eq $vmName}).PSComputerName
if($vmHost){
    invoke-command -computername $vmHost -scriptblock {
        param($vmName)$vmIsRunning=(get-vm $vmname).State -eq 'Running'
        if($vmIsRunning){stop-vm $vmName -Force}
        Set-VMProcessor $vmName -CompatibilityForMigrationEnabled 1
        if($vmIsRunning){start-vm $vmName}
    } -Args $vmName
}else{
    write-host "VMName $vmName doesn't match an existing record."
}

PowerShell: Search for Hyper-V Guest VM That Has Not Been Registered In Cluster

# findVmHost.ps1

$vmName='TESTVM01'

function findVmHost($vmName){
    try{
        Import-Module Hyper-V
        Import-Module FailoverClusters
        $allHyperVHosts={(Get-ClusterNode | Where { $_.State –eq "Up" }).Name | %{$_.ToLower()}}.Invoke()
        $allVms=foreach ($hyperVHost in $allHyperVHosts){invoke-command -computername $hyperVHost -scriptblock{write-host "Getting VM List on $env:computername";Get-VM |select Name,Path}|select-object * -ExcludeProperty RunspaceId,PSShowComputerName}
        $matchedHost=$allVms|?{$_.Name -like "*$vmName*"}
        if($matchedHost){
            return $matchedHost
        }else{
            write-host "'$vmName' is not found in cluster '$((get-cluster).Name)'"
            return $null
        }
    }catch{
        write-warning $_
        return $false
    }
}

findVmHost $vmName

Resolving Guest Virtual Machine Critical Status in Hyper-V Manager

Part A: Validating problem as VM in Critical Status

# Check VM Status in Hyper-V
$vmName='TESTVM.kimconnect.com'
get-vm $vmName

# Sample output
Name                      State       CPUUsage(%) MemoryAssigned(M) Uptime   Status
----                      -----       ----------- ----------------- ------   ------
TESTVM.kimconnect.com     OffCritical 0           0                 00:00:00 Cannot connect to virtual machine confi...

# Check storage locations
Get-VM $vmName | fl *Location, Path

# Sample output
CheckpointFileLocation : \\NAS\VMS\TESTVM.kimconnect.com
ConfigurationLocation  : \\NAS\VMS\TESTVM.kimconnect.com\config
SnapshotFileLocation   : \\NAS\VMS\TESTVM.kimconnect.com
Path                   : \\NAS\VMS\TESTVM.kimconnect.com\config

Part B: Refresh Hyper-V Virtual Machine Management Service

# Restart Virtual Machine Management Service from VMM Server
$vmName='TESTVM.kimconnect.com'
$vmInfo=Get-SCVirtualMachine -Name $vmName
#$badVmConfig=$vmInfo|?{$_.Status -eq 'IncompleteVMConfig'}
$currentHosts=$vmInfo.VMHost.FullyQualifiedDomainName

function restartService($serviceName){
    $waitSeconds=40
    $isValidProcess=try{[bool](get-service $serviceName -EA Stop)}catch{$false}
    if($isValidProcess){
        try{
            $process=Start-Process -FilePath powershell.exe -ArgumentList "-Command Restart-Service $serviceName" -PassThru -NoNewWindow
            $process|Wait-Process -Timeout $waitSeconds -ErrorAction Stop
            return $true
        }catch{
            write-warning $_
            $process|Stop-Process -Force
            $processId=(get-process $serviceName).Id
            if($processId){
                write-host "Program now forcefully kills PID $processId of process $serviceName"
                $null=$processId|%{taskkill /f /pid $_} # works more reliably than Stop-Process $processName -Force
                Start-Service $serviceName -ErrorAction Ignore
                $started=$(try{get-service $serviceName}catch{$false})
                if($started){
                    write-host "'serviceName' status is now $($started.Status)"
                    return $true
                }else{
                    write-warning "'serviceName' status is $($started.Status)"
                    return $false
                }
            }else{
                write-warning "Service '$serviceName' PID not found."
                return $false         
            }
        }
    }
}

$currentHosts|%{invoke-command -computername $_ {param($restartService,$serviceName);write-host "$env:computername";[scriptblock]::create($restartService).invoke($serviceName)}} -Args ${function:restartService},'vmms'

Part C: Guest VM shows as online

# Checking VM while login to Hyper-V Host
PS C:\Windows\system32> get-vm $vmName
get-vm : Hyper-V was unable to find a virtual machine with name "TESTVM.kimconnect.com".
At line:1 char:1
+ get-vm $vmName
+ ~~~~~~~~~~~~~~
    + CategoryInfo          : InvalidArgument: (TESTVM.kimconnect.com:String) [Get-VM], VirtualizationException
    + FullyQualifiedErrorId : InvalidParameter,Microsoft.HyperV.PowerShell.Commands.GetVM

# Checking VM while login to VMM
PS C:\Windows\system32> (Get-SCVirtualMachine -Name $vmName).VMHost.FullyQualifiedDomainName
HYPERV01
HYPERV07 (bad record)

# Find bad VM config on VMM Server
$vmName='TESTVM.kimconnect.com'
$vmInfo=Get-SCVirtualMachine -Name $vmName
$badVmConfig=$vmInfo|?{$_.Status -eq 'IncompleteVMConfig'}
$badVmConfig|write-host

# Example of failed repair
Repair-SCVirtualMachine : This action is not valid because virtual machine TESTVM.kimconnect.com is in state
Incomplete VM Configuration. The repair action can only be used on a virtual machine in a failed state. (Error ID: 693)

At line:1 char:1
+ Repair-SCVirtualMachine -VM $badRecord -Retry
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : ReadError: (:) [Repair-SCVirtualMachine], CarmineException
    + FullyQualifiedErrorId : 693,Microsoft.SystemCenter.VirtualMachineManager.Cmdlets.RepairVmCmdlet

PS C:\Windows\system32> refresh-vm $badRecord
refresh-vm : An internal error has occurred trying to contact the 'HYPERV01' server: NO_PARAM: NO_PARAM.
WinRM: URL: [http://HYPERV01:5985], Verb: [ENUMERATE], Resource:
[http://schemas.microsoft.com/wbem/wsman/1/wmi/root/microsoft/windows/storage/MSFT_Volume], Filter: []
 (Error ID: 2912, Detailed Error: The requested resource is in use (0x800700AA))

Check that WS-Management service is installed and running on server 'HYPERV01'. For more information
use the command "winrm helpmsg hresult". If 'HYPERV01' is a host/library/update server or a PXE server
role then ensure that VMM agent is installed and running. Refer to http://support.microsoft.com/kb/2742275 for more
details.

To restart the job, run the following command:
PS> Restart-Job -Job (Get-VMMServer localhost | Get-Job | where { $_.ID -eq "{26ce1506-da92-42a7-a400-705fe1008188}"})
At line:1 char:1
+ refresh-vm $badRecord
+ ~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : ReadError: (:) [Read-SCVirtualMachine], CarmineException
    + FullyQualifiedErrorId : 2912,Microsoft.SystemCenter.VirtualMachineManager.Cmdlets.RefreshVmCmdlet