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 : Richard@Manticore.org

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 *

Posted in PowerShell and Active Directory | Leave a comment

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 {
[CmdletBinding()]
param (
[string]$classname
)

$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
}

$props

}

 

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

etc

 

 

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

Name                          Read Write
—-                          —- —–
Caption                       True False
Description                   True False
InstallDate                   True False
<truncated>

ErrorMethodology              True False
NumberOfBlocks               False False
Purpose                       True False
<truncated>
VolumeDirty                   True False
VolumeName                    True  True
VolumeSerialNumber            True False

Posted in CIM, PowerShell and WMI | Leave a comment

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

Posted in PowerShell v5 | Leave a comment

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.

Posted in Learning Powershell | Leave a comment

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
   indingException
    + 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.

Posted in Powershell Basics | Leave a comment

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)
$Doc.Activate()   

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

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

$objCC.DropdownListEntries.Add(“PowerShell”)
$objCC.DropdownListEntries.Add(“Ruby”)
$objCC.DropdownListEntries.Add(“Perl”)

 

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.

Posted in Office 2013, Powershell | Leave a comment

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

and
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.

Posted in Powershell Basics | Leave a comment