Selecting AD properties

Saw a question on the forums about selecting name properties using the Microsoft AD cmdlets.  By default Get-AdUser returns a limited subset of properties:

£> Get-ADUser -identity richard

DistinguishedName : CN=Richard,CN=Users,DC=Manticore,DC=org
Enabled           : True
GivenName         :
Name              : Richard
ObjectClass       : user
ObjectGUID        : 7c42be70-c6b2-401f-8296-46de9ee7446c
SamAccountName    : Richard
SID               : S-1-5-21-195014076-723736408-1406369008-1104
Surname           :
UserPrincipalName :


Given name = first name


if you want other properties you have to explicitly aske for them using the –Properties parameter. You can use a wildcard * but if you have a big AD that could be a lot of unrequired data you are pulling back. On the other hand if you want a lot of properties its often simpler to use the wildcard. As with most PowerShell related things there is no answer that is right all of the time.


The user asking the question wanted the first name, last name and department for all users in a given OU.  Use the OU as the –SearchBase.  The property you need to explicitly ask for is Department:

£> Get-ADUser -Filter *  -SearchBase 'OU=Testing,DC=Manticore,DC=org' -Properties Department | select GivenName, SurName, Department | fl *

GivenName  : Dave
SurName    : Green
Department : Testing


Selecting AD properties can be a little bit awkward if you forget that the default set is limited.  If in doubt of a property name – display them all for one user:

Get-ADUser -identity richard -Properties *

WMI — identifying writable properties

One common mistake I see is people trying to set the value of a read only property on a WMI class.  There isn’t a quick way to see if a property is writable. Get-CimClass can be used but you have to dig into the Qualifiers for each property.


You can use this function to determine the read\write settings on all of the properties of a WMI class

function get-cimreadwriteproperties {
param (

$props = @()

$class = Get-CimClass -ClassName $classname
$class.CimClassProperties |
foreach {
  $prop = [ordered]@{
    Name = $psitem.Name
    Read = $false
    Write = $false
  $psitem |
  select -ExpandProperty Qualifiers |
  foreach {
    if ($_.Name.ToLower() -eq 'read') {
      $prop.Read = $true
    if ($_.Name.ToLower() -eq 'write') {
      $prop.Write = $true

  $props += New-Object -TypeName PSObject -Property $prop




Take the class name as a parameter and use Get-CimClass. Iterate through the properties and foreach create an output object. Test each qualifier to determine if read or write and set out to true. Add to array and output.


The output looks like this


£> get-cimreadwriteproperties -classname Win32_bios | ft -AutoSize

Name                  Read Write
----                  ---- -----
Caption               True False
Description           True False
InstallDate           True False
Name                  True False
Status                True False
BuildNumber           True False




£> get-cimreadwriteproperties -classname Win32_LogicalDisk | ft -AutoSize

Name                          Read Write
----                          ---- -----
Caption                       True False
Description                   True False
InstallDate                   True False

ErrorMethodology              True False
NumberOfBlocks               False False
Purpose                       True False
VolumeDirty                   True False
VolumeName                    True  True
VolumeSerialNumber            True False

Delivering PowerShell code

Do you have a need to deliver PowerShell code to multiple machines. I do. I have a dev environment plus test and production environments. I need to move code from dev through test and production.


One way to do this is to create all of your code as modules and use the PowerShell 5.0 feature – PowerShellGet.


This feature enables you to install modules from a central repository. The default is a public, cloud based, repository but you can create your own.


I’m going to investigate the possibilities in a series of posts

Learning PowerShell

I’ve been thinking about how people learn PowerShell through watching some people at work who are learning it and watching the questions on the forums – many of which start off “I’m new to PowerShell and…”


There seems to be two broad approaches:

Option 1 is to get some training. This could be a formal course, video training or the excellent Learn PowerShell in a Month of Lunches book. Then find problems to solve.


Option 2 takes the opposite approach and finds the problems to solve then starts figuring out how to use PowerShell to solve them.


Which route you take depends on a number of things:

how you like to learn

the environment you work in – can you actually find time to start using PowerShell, and approval,

the technologies you work with


The options above both assume that scripting is your end goal. I’d suggest one other approach that may help. Use the cmdlets you have directly from the command line.  You can accomplish a lot by piping a few cmdlets together. This gets you used to working with cmdlets and the PowerShell language.


Keep it Simple and start small. You’ll soon start progressing.

What Formatting cmdlets do to your data

I have seen an increasing number of questions recently where the answer has been to remove Format-Table from the pipeline. As an example consider the names of the processes running on your machine

Get-Process -Name calc | Stop-Process


works because you are piping the selected object into the Stop-Process cmdlet.

Now think about this

Get-Process -Name calc | select Name | Stop-Process


a bit more long winded (the select isn’t necessary) but the resultant object hitting Stop-Process identifies a process by name which is all Stop-Process needs to work.


As a way to approach the reason for the first sentence in the post is there any difference between these two statements?

Get-Process -Name calc

Get-Process -Name calc | Format-Table


The output to screen looks identical. So  I should be able to do this:

Get-Process -Name calc | Format-Table | Stop-Process


What I get is a bunch of errors of the form:

Stop-Process : The input object cannot be bound to any parameters for the command either because the command does not take pipeline input or the input and its properties do not match any of the parameters that take pipeline input.
At line:1 char:41
+ Get-Process -Name calc | Format-Table | Stop-Process
+                                         ~~~~~~~~~~~~
    + CategoryInfo          : InvalidArgument: (Microsoft.Power...FormatStartData:PSObject) [Stop-Process], ParameterB
    + FullyQualifiedErrorId : InputObjectNotBound,Microsoft.PowerShell.Commands.StopProcessCommand


The reason for this is simple.  The Format cmdlets destroy your pipeline and objects.  They take what they are given and output formatting directives. The only thing you can do with them is display them on screen (you can pipe to a text file but effectively the same thing)


If in doubt about what you’re dealing with at any time use Get-member

£> Get-Process | Get-Member

   TypeName: System.Diagnostics.Process


£> Get-Process | select name | Get-Member

   TypeName: Selected.System.Diagnostics.Process


Notice the slight change in that its now Selected.System.Diagnostics.Process instead of System.Diagnostics.Process

This only applies if you’re selecting a subset of properties. If you want the first N objects


£> Get-Process | select -First 5 | Get-Member

   TypeName: System.Diagnostics.Process


You still have the original type.


However, lets look at formatting

£> Get-Process | Format-Table | Get-Member

TypeName: Microsoft.PowerShell.Commands.Internal.Format.FormatStartData

TypeName: Microsoft.PowerShell.Commands.Internal.Format.GroupStartData

TypeName: Microsoft.PowerShell.Commands.Internal.Format.FormatEntryData

TypeName: Microsoft.PowerShell.Commands.Internal.Format.GroupEndData

TypeName: Microsoft.PowerShell.Commands.Internal.Format.FormatEndData


You get 5 different objects out – none of which have anything to do with your processes – apart from the values.

The Format cmdlets are designed to format your data for display. Thats all they do. Once your data hits the Format cmdlets that data can only be used fro display – nothing else. Put your Format cmdlets at the end of your pipeline and don’t attempt to do anything else with the data.

Add a drop down to a Word document


Its surprisingly easy to programatically add a drop down list to Word document


$Word = New-Object -Com Word.Application
$word.visible = $true
$template = "c:\test\template.docx"  
$Doc = $Word.Documents.Open($template)

$cntrl = [Enum]::Parse([Microsoft.Office.Interop.Word.WdContentControlType], "wdContentControlDropdownList")

$objCC = $doc.ContentControls.Add($cntrl)



Create the COM object for Word and set visible.  Open a template (in this case a blank document) file and activate.


Set the type of control you want to add and define the possible entries.


It should be possible to set the default text but the method for doing that appears to be very awkward.  I’ll publish that if I work it out.

The little changes that make a difference

Each version of PowerShell introduces a new headline feature – remoting, workflows, DSC, OneGet in version 2,3,4 and 5 respectively. While this can change the way we work there are also a host of little changes that come along that are often overlooked.


One example is a change to Get-ChildItem introduced in PowerShell 3.0.


Consider getting a directory listing:

Get-ChildItem -Path C:\Windows


This will give all subfolders and file in the given folder.


If you just wanted the files you had to do this:

Get-ChildItem -Path C:\Windows | where {$_.PSIsContainer}


If you want just the files you use:
Get-ChildItem -Path C:\Windows | where {-not $_.PSIsContainer}


or the slightly shorter but not as easy to read:
Get-ChildItem -Path C:\Windows | where {!$_.PSIsContainer}


The PSIsContainer property name is not intuitive and I rarely remember the name exactly and try ISPSContainer first or some other variant.


Two additional filtering parameters were added to Get-ChildItem

Get-ChildItem -Path C:\Windows –Directory


Get-ChildItem -Path C:\Windows -File


produce listings of folders and files respectively.


A small simple change that makes life easier.


There are a lot of small changes like this scattered through the later PowerShell versions – I’d recommend going through the release notes to track down the ones that will be useful to you.

Persisting PowerShell Objects

I was asked recently about persisting PowerShell objects. The idea was to test a particular property on a semi-regular basis and save the object with the highest value for the property.  If the next test has a higher value it is saved and overwrites the existing object.


There are a number of ways to do this – if you are running the test very frequently then you could keep the object in memory as a variable. If you are testing fairly infrequently then you may want to persist the object to disk.  The CliXml cmdlets are good for this.


Start by creating a reference object:

Get-Process -Name powershell | Export-Clixml -Path proc1.xml


Then run some more tasks in PowerShell to increase the CPU usage. You can do this with any property that will change over time.  CPU is an easy example. You can then run your test. I used an instance of ISE to do the test so I didn’t alter the value by running the test.


$proc = Get-Process -Name powershell

Get-ChildItem -Path .\proc1.xml

$psp = Import-Clixml -Path .\proc1.xml

if ($proc.CPU -gt $psp.CPU){

$proc | Export-Clixml -Path proc1.xml


Get-ChildItem -Path .\proc1.xml


Get the current data and test the saved file. Import the saved file.  Test the CPU values and if the new value is higher save the object by overwriting the file.  Repeat as required.


The help files for Export-CliXml and Import-CliXml should be read.

1,000,000 hits on this blog this year

Yesterday this blog alone went over the 1,000,000 hits for the year – if you include its mirror sites that comes to over 1,240,000 in total for this year


Thank you to everyone who has taken the time to read my posts

PowerShell Summit Europe 2015 – – topics to include

Are you planning on attending the PowerShell Summit Europe 2015.  If so what topics would you like to see covered. The Summit is deliberately pitched at a high level so you won’t find beginner level content.


If there’s a topic you’d like to be included in the agenda – leave a comment explaining what it is and why you think it would make a good Summit topic. No promises but we’ll see what we can do