Uninstall Application with Server Core

There is no way to directly uninstall a program with PowerShell, but you can get there in a PSRemote Session using WMI.  Note, this won’t work for Nano since it doesn’t have WMI.

First you need to open your connection and get the programs with WMI.

Enter-PSSession - ComputerName <YOURCOMPUTER>
$programs = Get-WmiObject -Class win32_product
$programs | Select Name

Now you can see the installed programs.  Find the one you want to remove, counting from zero to get its index in the array.  I want to remove program 5 in my example.  To test, I run a quick command to make sure I have the right entry.


If you get the right program back, proceed to uninstall.


You can rerun the initial commands to make sure it is no longer listed.  When you’re done, make sure to exit your PSRemote session.


Block SMB to your Workstations

When was the last time you had a business need to reach the C$ share on one of your workstations?  When was the last time you wanted a user workstation to reach the C$ share on another workstation?

If your answer was never or rarely, then you should block them.  It helps slow lateral movement of an attacker and if you were unpatched against MS17-010, but had this in place it would have prevented the spread of WannaCry.

This has been available since the introduction of the integrated firewall in Windows XP SP2.  It can be configured by Group Policy, so it’s easy to have it automatically applied to new machines as they are put into production.

Modify DPM Schedule with PowerShell

We recently ran into an issue where we wanted to update the backup schedules for a number of our protection groups.  I did one through the GUI and then decided to write up something in PowerShell.  This script is built to copy the settings from one protection group to another, so you do need to use the GUI once to set it up, or you could use these commands to do that initial change in PowerShell as well.

The odd thing is that you can’t actually copy a schedule from one to the other, so you put the schedule into a variable and pull out the pieces to copy it over.

$PG = Get-DPMProtectionGroup -DPMServerName <YOURDPMSERVER>
for ($i=0;$i -le ($pg.Count-1);$i++) {
Write-Output ('[' + $i.ToString() +'] ' + $pg[$i].Name)
$pgchoice1 = Read-Host -Prompt 'Choose Protection Group to copy schedule FROM'

$sched = Get-DPMPolicySchedule -ProtectionGroup $PG[$pgchoice1] -ShortTerm

for ($i=0;$i -le ($pg.Count-1);$i++) {
Write-Output ('[' + $i.ToString() +'] ' + $pg[$i].Name)
$pgchoice2 = Read-Host -Prompt 'Choose Protection Group to copy schedule TO'

$MPG = Get-DPMModifiableProtectionGroup -ProtectionGroup $PG[$pgchoice2]

Set-DPMPolicySchedule -ProtectionGroup $MPG -Schedule (Get-PolicySchedule $MPG -ShortTerm) -DaysofWeek $sched.WeekDays -TimesOfDay $sched.TimesOfDay

Set-DPMProtectionGroup -ProtectionGroup $MPG

Modify Replica Size with PowerShell

With DPM you may get errors that the DPM is out of disk space for the replica. (ID 58 Details: There is not enough space on the disk (0x80070070))  Assuming you’re not actually out of space, the replica size just needs to be increased.
Unfortunately, the menu option to Modify disk allocation isn’t selectable.
Luckily, we have PowerShell.  NOTE: These scripts assume you’re local to the DPM server, if not you’ll need to add on the -DPMServer switch to the initial commands.
First, we need to get the list of protection groups.  This script block pulls the groups into an array, then outputs their names with the array index.
$pg = Get-DPMProtectionGroup
for ($i=0;$i -le ($pg.Count-1);$i++) {
Write-Output ('[' + $i.ToString() +'] ' + $pg[$i].Name)
Now that you can get the name of the protection group, run the next script block with the index of that entry (in this example, I’m grabbing the second PG, or index 1).  The second bit outputs the datasources in the protection group with their index value in the array and the datasource name.
$ds = Get-DPMDatasource -ProtectionGroup $pg[1]
for ($i=0;$i -le ($pg.Count-1);$i++) {
Write-Output ('[' + $i.ToString() +'] ' + $ds[$i].Name)
Now you can grab the datasource you need to modify.  This script block grabs the individual datasource from the array of datasources, then outputs the name (to make sure you’ve got the right one) and then shows you the current replica size, in GB.
$d = $ds[0]
We can now modify the replica size.  Make sure you update the value for the ReplicaSize switch to match what you need.
Edit-DPMDiskAllocation -Datasource $d -ReplicaSize (24*1024*1024*1024)
Once that completes the Replica should have been resized.  You can use the UI to start a consistency check, but we’re in PowerShell, so let’s just do that here as well.
$cc = Start-DPMDatasourceConsistencyCheck -Datasource $d
Write-Output $cc.Status

Setup New Disk on 2016 Server Core

When adding a disk to a server core machine, we don’t have the GUI and will need to use PowerShell to finish the disk setup.

To start, you’ll want to use Get-Disk to show your disks, you’ll want to note the disk number of the new disk you are setting up.  For this example, I’ll be working with disk 2.


Then you need to make sure the disk is online and set to read/write (by default it will be offline and read-only).

Get-Disk -Number 2 | Set-Disk –IsOffline:$false
Get-Disk -Number 2 | Set-Disk –IsReadOnly:$false

Then you need to initialize the disk, create a partition, and format it.  We can do all of this in one command.  Be careful that you’ve picked the right disk!

Get-Disk -Number 2 | Initialize-Disk –Passthru | New-Partition -AssignDriveLetter -UseMaximumSize | Format-Volume -FileSystem NTFS -Confirm:$false –Force

Note that it automatically picks the first free drive letter.  In this case, it picked drive F.


If you want to use a different drive letter, you need to mix some PowerShell and WMI to make the change.  In my example I’m going to change drive F to be drive S.

$drive = Get-WMIObject –Class win32_volume –Filter "DriveLetter = 'f:'"
Set-WMIInstance –input $drive –arguments @{DriveLetter="s:"}

Once you’re all done, you can use Get-Volume to make sure everything is set the way you want.

Office 365 – Outlook Autodiscover Fails

So, the Autodiscover for Office 365 just doesn’t work, sometimes.  We happened to be in that boat, and we tried checking the domain in Office 365 (everything is set up correctly), tried the Microsoft Remote Connectivity Analyzer (also said everything is fine), and tried changing group policies to disable some of the Autodiscover methods (now it fails faster).

So we were down to using the Office 365 Support and Recovery Assistant to set up every new profile.  This is slow and can’t set up profiles that connect to more than on tenant (since it forces you to create a new profile each time you run it).

Fortunately, in this guide (https://www.howto-outlook.com/howto/autodiscoverconfiguration.htm) to setting up Autodiscovery, it mentions using a local autodiscover.xml file.  I was able to set this up, so it has the redirection information, so Outlook can go right to it, fixing all our setup problem.

Between our two tenants, the xml file was the same, so hopefully this is a universal and can work for you too.

First, create your xml file (the file name doesn’t matter as long as you know it later):

<?xml version="1.0" encoding="utf-8" ?>
<Autodiscover xmlns="http://schemas.microsoft.com/exchange/autodiscover/responseschema/2006">
  <Response xmlns="http://schemas.microsoft.com/exchange/autodiscover/outlook/responseschema/2006a">

Now, you need to add a registry key to make Outlook use this file.  Create a new REG_SZ key in HKEY_CURRENT_USER\SOFTWARE\Microsoft\Office\16.0\Outlook\AutoDiscover, the value name is the mail domain you’re using, the value is the path to the xml file.

You can bundle this part up with PowerShell:

$localpath = "C:\autodiscover"
$autodfile = "autodiscover.xml"
$regpath = 'HKCU:\SOFTWARE\Microsoft\Office\16.0\Outlook\AutoDiscover'
$key = 'mail.domain'
$value = ($localpath+'\'+$autodfile)
#check if the key is already there
$out = $null
$out = Get-ItemProperty -Path $regpath -Name $key -ErrorAction SilentlyContinue
#add key if not present
if (!$out) { New-ItemProperty -Path $regpath -Name $key -Value $value -PropertyType String }


VM Switch Team on Windows Server 2016 Nano

So you’ve set up your Nano server to work as a Hyper-V host, and now you’re ready to configure your teamed VM switch.  Except you’re on Nano and have no console to do it, and only two NICs.  What to do?

Well, you can get there, it just takes a little bouncing around.

Configure one of your NICs (make sure to note the MAC address) with an IP on your network so that you can make a connection.  Leave the other NIC unconfigured.

Now you can connected with PowerShell.  You first have to add the IP of the remote Nano server to a Trusted Hosts list for WinRM:

Set-Item WSMan:\localhost\Client\TrustedHosts -Value

Now you can create your remote session:

Enter-PSSession -ComputerName -Credential HostName\Administrator

Now get your network adapters:


If you want to rename them, do that now:

Get-NetAdapter -Name 'Ethernet' | Rename-NetAdapter -NewName Team1
Get-NetAdapter -Name 'Ethernet 1' | Rename-NetAdapter -NewName Team2

Check to see which NIC you’re using now.  I’ll assume that is Team1, so we’re create your VM Switch with just Team2:

New-VMSwitch -Name TeamedvSwitch -NetAdapterName "Team2" -EnableEmbeddedTeaming $true -AllowManagementOS $false

Now check that the team was created correctly:


Now you can add a management NIC and configure it (replace values as necessary for your environment):

Add-VMNetworkAdapter -ManagementOS -Name "Management" -SwitchName "TeamedvSwitch"
Set-VMNetworkAdapterVlan -ManagementOS -VMNetworkAdapterName "Management" -Access -VlanId 2
New-NetIPAddress –InterfaceAlias "vEthernet (Management)" –IPAddress –PrefixLength 24 -DefaultGateway
Set-DnsClientServerAddress -InterfaceAlias "vEthernet (Management)" -ServerAddresses,

Now you need to exit your remote session:

Then set up a rule to allow a connection to the new Team:
Set-Item WSMan:\localhost\Client\TrustedHosts -Value
Now you can connect to the server on the new connection:
Enter-PSSession -ComputerName -Credential HostName\Administrator
Now you just need to add the Team1 NIC into the team:
Set-VMSwitchTeam -Name TeamedvSwitch -NetAdapterName "Team1","Team2"
Now your team is set up and you’re ready to start setting up the rest of your server.  Don’t forget to close out your session when you’re done.