PowerShell for Windows Admins

November 17, 2016  10:16 AM

New PowerShell console on Server Core

Richard Siddaway Richard Siddaway Profile: Richard Siddaway
Powershell, Windows Server 2012, Windows Server 2012 R2, Windows Server 2016

Server Core is great for reducing the footprint of your VMs – Nano server is smaller but it can’t be a domain controller

One draw back to server core is that you only get a single console. If you hang that for any reason you have to either try and open another one (Hyper-V console greys out CTRL-DEL-ALT) or open a few when you logon to the machine.

You still get a cmd.exe console instead of PowerShell – that should be changed. Its 10 years since PowerShell came along! So run Powershell to open  Powershell in the default console.

“Start-Process -FilePath powershell.exe -Verb RunAS” > new-powershell.ps1

Will create a simple script to open a new elevated Powershell console.

Run it as many times as you want. Perform your work in the new Powershell console and if it hangs – just shut it down. Keep the default console for just opening new PowerShell consoles and then you’ll always be able to keep working.

November 17, 2016  8:18 AM

Creating test accounts in Active Directory

Richard Siddaway Richard Siddaway Profile: Richard Siddaway
Active Directory, Powershell

There’s often a need to create test accounts in AD. You may want to create a a set of test accounts or if you have a demo/test lab you may need accounts in that. Creating the names for the accounts is a pain unless you go down the test1, test2 etc route.

One way to real looking names is I use a couple of loops like this:

$fnames = @(

$lnames = @(

$secpass = Read-Host -Prompt 'Password' -AsSecureString
$ou = "OU=UserAccounts,DC=Manticore,DC=org"

foreach ($fname in $fnames){
  foreach ($lname in $lnames){
    $name = $lname.TOUpper() + " $fname"
    $sam = "$fname$lname"
    $upn = "$sam@manticore.org"

    New-ADUser -Name $name -SamAccountName $sam -UserPrincipalName $upn -AccountPassword $secpass -Path $ou -Enabled $true

First create an array of first names & another array of second names

Get a secure string for the Password – I’m using the same password for all as its my demo/test environment

Set the OU you want the accounts in.

Iterate over the set of first names and in that loop iterate over the last name. Within the inner loop create the name, samAccountName and UPN and call New-ADUser.

You end up with a set of new accounts where every first name is joined with every last name to create accounts. Names look a bit samey but for demo environment it works. Also, saves you having to think up individual names.

I’ve used 10 names in each of the first and last name arrays so end up with 100 new accounts.

November 16, 2016  11:22 AM

Exploring PowerShell automation

Richard Siddaway Richard Siddaway Profile: Richard Siddaway
Books, Powershell

My PowerShell books have all been published by Manning, A while back they asked me to put together a selection of extracts that show the depth and breadth of PowerShell. Its now available – for free – https://www.manning.com/books/exploring-powershell-automation

The book highlights PowerShell remoting and administering SQL Server, IIS and Active Directory through PowerShell. These are core skills these days and the book will give you a good introduction to these areas

November 15, 2016  12:48 PM

PowerShell 10 year anniversary videos

Richard Siddaway Richard Siddaway Profile: Richard Siddaway

Yesterday was the PowerShell 10 year anniversary event – broadcast live on channel 9

The session recordings are available


November 11, 2016  11:29 AM

Hyper-V book

Richard Siddaway Richard Siddaway Profile: Richard Siddaway
book, Hyper-V

I’ve been working with Andy Syrewicze on Learn Hyper-V in a Month of Lunches.

Its now available in Manning’s Early Access program (MEAP) https://www.manning.com/books/learn-hyper-v-in-a-month-of-lunches

Until 14 November 2016 you can get the MEAP for half price using code mlsyrewicze

November 5, 2016  10:59 AM

Creating a new AD forest

Richard Siddaway Richard Siddaway Profile: Richard Siddaway
Active Directory, Powershell, Windows Server 2016

As I’ve completely rebuilt my demo/lab machine I need to re-create the Active Directory

This is now so simple even on a server core machine

First install the roles and features needed

Add-WindowsFeature -Name AD-Domain-Services, RSAT-AD-PowerShell, DNS, RSAT-DNS-Server, DHCP, RSAT-DHCP

This adds AD, DNS, DHCP and the appropriate admin tools – as its server core we’re really talking about the relevant PowerShell modules

Installing AD just gets you ready – it doesn’t create the forest

You get the ADDSDeployment module

PS C:\Scripts> Get-Command -Module ADDSDeployment


To create the forest and the first domain controller

PS C:\Scripts> Install-ADDSForest -DomainName ‘Manticore.org’ -ForestMode Default -DomainMode Default -InstallDns
SafeModeAdministratorPassword: ********

You’ll be asked to confirm the safe mode password

Default for forest and domain mode matches the Windows version

PS C:\Users\Administrator> Get-ADForest
ApplicationPartitions : {}
CrossForestReferences : {}
DomainNamingMaster    : W16DC01.Manticore.org
Domains               : {Manticore.org}
ForestMode            : Windows2016Forest
GlobalCatalogs        : {W16DC01.Manticore.org}
Name                  : Manticore.org
PartitionsContainer   : CN=Partitions,CN=Configuration,DC=Manticore,DC=org
RootDomain            : Manticore.org
SchemaMaster          : W16DC01.Manticore.org
Sites                 : {Default-First-Site-Name}
SPNSuffixes           : {}
UPNSuffixes           : {}


PS C:\Users\Administrator> Get-ADDomain
AllowedDNSSuffixes                 : {}
ChildDomains                       : {}
ComputersContainer                 : CN=Computers,DC=Manticore,DC=org
DeletedObjectsContainer            : CN=Deleted Objects,DC=Manticore,DC=org
DistinguishedName                  : DC=Manticore,DC=org
DNSRoot                            : Manticore.org
DomainControllersContainer         : OU=Domain Controllers,DC=Manticore,DC=org
DomainMode                         : Windows2016Domain
DomainSID                          : S-1-5-21-759617655-3516038109-1479587680
ForeignSecurityPrincipalsContainer : CN=ForeignSecurityPrincipals,DC=Manticore,DC=org
Forest                             : Manticore.org
InfrastructureMaster               : W16DC01.Manticore.org
LastLogonReplicationInterval       :
LinkedGroupPolicyObjects           : {CN={31B2F340-016D-11D2-945F-00C04FB984F9},CN=Policies,CN=System,DC=Manticore,DC=o
LostAndFoundContainer              : CN=LostAndFound,DC=Manticore,DC=org
ManagedBy                          :
Name                               : Manticore
NetBIOSName                        : MANTICORE
ObjectClass                        : domainDNS
ObjectGUID                         : 05d9aa61-d422-4728-9595-77754934b948
ParentDomain                       :
PDCEmulator                        : W16DC01.Manticore.org
PublicKeyRequiredPasswordRolling   : True
QuotasContainer                    : CN=NTDS Quotas,DC=Manticore,DC=org
ReadOnlyReplicaDirectoryServers    : {}
ReplicaDirectoryServers            : {W16DC01.Manticore.org}
RIDMaster                          : W16DC01.Manticore.org
SubordinateReferences              : {CN=Configuration,DC=Manticore,DC=org}
SystemsContainer                   : CN=System,DC=Manticore,DC=org
UsersContainer                     : CN=Users,DC=Manticore,DC=org

November 4, 2016  10:51 AM

ComputerName parameters for CIM and WMI cmdlets

Richard Siddaway Richard Siddaway Profile: Richard Siddaway
CIM, Powershell, WMI

Accessing a remote system and running

Get-WmiObject -ClassName Win32_LogicalDisk -ComputerName $computer


Get-CimInstance -ClassName Win32_LogicalDisk -ComputerName $computer

is a standard approach.

If you’re creating a function with that code in you may put the local machine as a default parameter:

$computer = $env:COMPUTERNAME

Running Get-WmiObject locally will work quite happily because you’re using COM to access the local machine.

Get-CimInstance may well fail with this error

PS> Get-CimInstance -ClassName Win32_LogicalDisk -ComputerName $computer
Get-CimInstance : The client cannot connect to the destination specified in the request. Verify that the service on the destination is running and is accepting requests. Consult the logs anddocumentation for the WS-Management service running on the destination, most commonly IIS or WinRM.
If the destination is the WinRM service, run the following command on the destination to analyze and configure the WinRM service: “winrm quickconfig”.
At line:1 char:1
+ Get-CimInstance -ClassName Win32_LogicalDisk -ComputerName $computer
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo          : ConnectionError: (root\cimv2:Win32_LogicalDisk:String) [Get-CimInstanc
e], CimException
+ FullyQualifiedErrorId : HRESULT 0x80338012,Microsoft.Management.Infrastructure.CimCmdlets.GetC
+ PSComputerName        : RSSURFACEPRO2

The CIM cmdlets use WSMAN to connect to remote machines. This is triggered by using the –ComputerName parameter. The error means you haven’t got the winrm service running on the local machine. On modern Windows remoting, and therefore winrm, are enable by default for servers but disable for client OS e.g. Windows 10. Easiest way to get this to work is run Enable-PSremoting from and elevated prompt.

November 4, 2016  10:03 AM

Working with multiple CIM objects

Richard Siddaway Richard Siddaway Profile: Richard Siddaway
CIM, Powershell, WMI

Many of the CIM objects we work with in our computers come in multiple instances – disks and network cards are a couple of examples. Many times when you see examples you’ll see something like this:

$disks = Get-WmiObject -Class Win32_LogicalDisk

foreach ($disk in $disks){
if ($disk.Size -gt 0) {
$disk | select DeviceId,
@{N=’Free’; E={[math]::Round($disk.FreeSpace/1GB, 2)}},
@{N=’Size’; E={[math]::Round($disk.Size/1GB, 2)}},
@{N=’PercUsed’; E={[math]::Round((($disk.Size – $disk.FreeSpace) / $disk.Size) * 100, 2)}}

Get a collection of objects. Iterate through them with foreach and do something.

You can, and should, do this as a pipeline operation. The code above is really a hangover from VBScript coding.

Converting the above to a pipeline gives

Get-WmiObject -Class Win32_LogicalDisk |
where Size -gt 0 |
foreach {
$_ | select DeviceId,
@{N=’Free’; E={[math]::Round($_.FreeSpace/1GB, 2)}},
@{N=’Size’; E={[math]::Round($_.Size/1GB, 2)}},
@{N=’PercUsed’; E={[math]::Round((($_.Size – $_.FreeSpace) / $_.Size) * 100, 2)}}

NOTE – before anyone starts complaining yes I know you can use a  filter on Get-WmiObject I’m explaining the principle! Also, I know that you could go straight into the select on the pipeline but if you want to add extra processing e.g. send an email if the disk is more than 80% used you need the foreach

You can do similar things with NICs for example

Get-WmiObject -ClassName Win32_PerfFormattedData_Tcpip_NetworkInterface |
where CurrentBandwidth -gt 0 |
foreach {

$props = [ordered]@{
Name = $psitem.Name
Computer = $psitem.PSComputerName
PercUtilisation = (($psitem.BytesTotalPersec * 8) / $psitem.CurrentBandWidth) * 100

New-Object -TypeName PSObject -Property $props

} |
where PercUtilisation -gt 0.5 |
foreach {
$text =  @”
$($_.Name) on $($_.Computer)

Bandwidth utilized:  $($_.PercUtilisation) %



Rather than displaying $text send an email if the utilisation is too big.

where PercUtilisation -gt 0.5

is used so I actually get to see results. You probably want 60% or more on your production machines.

November 3, 2016  9:00 AM

New Hyper-V switch on Windows 10

Richard Siddaway Richard Siddaway Profile: Richard Siddaway
Hyper-V, Windows 10

My test/lab machine had been running Windows Server 2016 TP 5. With Server 2016 now RTM it was time for a rebuild.  Unfortunately, 2016 RTM carried on from TP5 and decided not to work with my wireless card.

Decided to try using Hyper-V on Windows 10 – it recognises the wifi card and is happy to work with it.

After installing the Hyper-V feature I needed to create some Hyper-v virtual switches

PS> New-VMSwitch -SwitchType External -Name ‘LAN’ -NetAdapterName ‘LAN’
New-VMSwitch : Cannot validate argument on parameter ‘SwitchType’. The argument “External” does not belong to the set
“Internal,Private” specified by the ValidateSet attribute. Supply an argument that is in the set and then try the
command again.
At line:1 char:26
+ New-VMSwitch -SwitchType External -Name ‘LAN’ -NetAdapterName ‘LAN’
+                          ~~~~~~~~
+ CategoryInfo          : InvalidData: (:) [New-VMSwitch], ParameterBindingValidationException
+ FullyQualifiedErrorId : ParameterArgumentValidationError,Microsoft.HyperV.PowerShell.Commands.NewVMSwitch

But External is a valid switch type

PS> New-VMSwitch -SwitchType x
New-VMSwitch : Cannot bind parameter ‘SwitchType’. Cannot convert value “x” to type
“Microsoft.HyperV.PowerShell.VMSwitchType”. Error: “Unable to match the identifier name x to a valid enumerator name.
Specify one of the following enumerator names and try again:
Private, Internal, External”
At line:1 char:26
+ New-VMSwitch -SwitchType x
+                          ~
+ CategoryInfo          : InvalidArgument: (:) [New-VMSwitch], ParameterBindingException
+ FullyQualifiedErrorId : CannotConvertArgumentNoMessage,Microsoft.HyperV.PowerShell.Commands.NewVMSwitch

Wonder how many of these issues I’m going to find!

October 31, 2016  10:52 AM

Don’t reinvent the wheel

Richard Siddaway Richard Siddaway Profile: Richard Siddaway
Powershell, Windows Server

Way back when I used to take Microsoft certification exams there were often questions of the form “Perform task X with the minimum of administrative effort” Most, if nor all, of the possible answers would be correct but the correct answer was the one that achieved the goal with the minimum amount of work.

Many, if not most, administrators don’t seem to follow that model.

This was brought home to me when I saw a forum discussion about collecting event log information from a bunch of remote servers on a regular basis.

You could set up a scheduled task/job that runs a script against the remote servers – collects the  log information and populates an Excel spreadsheet


You could enable event log forwarding and just interrogate the combined logs as needed.

The second option is the easier to MAINTAIN and will cost you less effort in the long run.

When you start to solve a problem – stop and search for a bit to see if there is a solution already available in Windows server. Bet you’ll be surprised by what you find

Forgot Password

No problem! Submit your e-mail address below. We'll send you an e-mail containing your password.

Your password has been sent to: