Test data for bulk AD changes

I’ve had a number of questions about changing AD user data in bulk. If you need to do that you need some test data. The specific questions were around setting the Division property and the EmployeeNumber at the same time – but some accounts didn’t have an employee number.

First you need to generate some test data

$count =  1

Get-ADUser -Filter * -SearchBase 'OU=UserAccounts,DC=Manticore,DC=org' |
foreach {
  $props = @{
    Id = $psitem.SamAccountName
    Division = ''
    EmployeeNumber = $count

  switch ($count % 3){
    0 {$props.Division = 'Division A'}
    1 {$props.Division = 'Division B'}
    2 {$props.Division = 'Division C'}

  if (-not ($count % 15)){$props.Remove('EmployeeNumber')}
  New-Object -TypeName PSObject -Property $props

  $count ++
} |
Export-Csv -Path users.csv –NoTypeInformation

You need a counter variable. Use Get-ADUser to get you test users and pipe to foreach. You can then create a hashtable for the properties – Id = samaccountname, Division is an empty string and EmployeeNumber is set equal to count.

A switch statement is used to modify the division. Modulo 3 on the $count variable can only give values of 0, 1 or 2.

Remove the EmployeeNumber for every 15th account

Create an object. Increment the counter.

Export the objects to a csv file.  You should end up with something like this:

Division   EmployeeNumber Id
--------   -------------- --
Division B 1              DonJones
Division C 2              DonSmith
Division A 3              DonBrown
Division B 4              DonBlack
Division C 5              DonWhite
Division A 6              DonGreen
Division B 7              DonWood
Division C 8              DonBell
Division A 9              DonHarris
Division B 10             DonFox
Division C 11             JamesJones
Division A 12             JamesSmith
Division B 13             JamesBrown
Division C 14             JamesBlack
Division A                JamesWhite
Division B 16             JamesGreen
Division C 17             JamesWood


Next time I’ll show you how to deal with the missing employee numbers when you modify the AD accounts.

Posted in PowerShell and Active Directory, Powershell Basics | Leave a comment

Get-Content and Numbers

A common technique is to put a list of information into a text file and read that using Get-Content. The information is often server names. This works great when the data is strings but breaks down if you’re dealing with numbers.

Lets start with a text file containing some numbers:

PS> Get-Content -Path .\num.txt

Let’s try and sort those numbers:

PS> Get-Content -Path .\num.txt | sort

It may seem that nothing is happening but if you sort descending:

PS> Get-Content -Path .\num.txt | sort -Descending

Things change but not quite in the way that you might think. The data isn’t being sorted numerically its being sorted as strings.

PS> Get-Content -Path .\num.txt | Get-Member

   TypeName: System.String

If you read the help file for Get-Content it states that the cmdlet returns either strings or bytes depending on the content of the file.

So if Get-Content returns strings what can we do if we want to work with the file contents as numbers rather than text.

You have a few choices. You can force a type conversion (known in programming circles as a cast) in a number of ways.

First using the –as operator

PS> Get-Content -Path .\num.txt | foreach {$psitem -as [int]} | sort

That’s more like a numeric sort

You can cut down on the code:

PS> Get-Content -Path .\num.txt | foreach {[int]$psitem} | sort

Or you can use foreach to call  a method on the object

PS> Get-Content -Path .\num.txt | foreach ToInt32($psitem) | sort

You can even use the foreach method on the array that Get-Content creates

PS> (Get-Content -Path .\num.txt).foreach({[int]$psitem})  | sort

The last option is the fastest but is only available on PowerShell 4.0 and above.

Get-Content returns strings but its not difficult to turn them into the numbers you need

Posted in Powershell Basics | Leave a comment


Wanted one nice kind PowerShell community member to buy the last lonely ticket for the 2017 PowerShell and DevOps Summit.

That’s right we have one place left. And its definitely the last. if you want it – better hurry.

Posted in Powershell, Summit | Leave a comment

Get-ADUser doesn’t display all properties

Microsoft’s Active Directory cmdlets have some issues. One of the ones that catches everyone when they start using them is that Get-ADUser doesn’t display all properties.

A default call to Get-ADUser displays a subset of the available properties of the user object:

DistinguishedName : CN=FOX Fred,OU=UserAccounts,DC=Manticore,DC=org
Enabled           : True
GivenName         :
Name              : FOX Fred
ObjectClass       : user
ObjectGUID        : db5a3975-980d-4749-b9c0-48aff9217b2a
SamAccountName    : foxfred
SID               : S-1-5-21-759617655-3516038109-1479587680-1314
Surname           :
UserPrincipalName : FredFox@manticore.org

Even if the properties are empty – such as Givenname and Surname – the property name is displayed. So, how do you get the properties that aren’t part of the default list?

There’s the brute force approach:

PS> Get-ADUser -Identity foxfred -Properties *

AccountExpirationDate                :
accountExpires                       : 9223372036854775807
AccountLockoutTime                   :
AccountNotDelegated                  : False
AllowReversiblePasswordEncryption    : False
AuthenticationPolicy                 : {}
AuthenticationPolicySilo             : {}
BadLogonCount                        : 0
badPasswordTime                      : 0
badPwdCount                          : 0
CannotChangePassword                 : False
CanonicalName                        : Manticore.org/UserAccounts/FOX Fred
Certificates                         : {}
City                                 :
CN                                   : FOX Fred
codePage                             : 0
Company                              :
CompoundIdentitySupported            : {}
Country                              :
countryCode                          : 0
Created                              : 17/11/2016 14:07:13
createTimeStamp                      : 17/11/2016 14:07:13
Deleted                              :
Department                           :
Description                          :
DisplayName                          :
DistinguishedName                    : CN=FOX Fred,OU=UserAccounts,DC=Manticore,DC=org
Division                             :
DoesNotRequirePreAuth                : False
dSCorePropagationData                : {01/01/1601 00:00:00}
EmailAddress                         :
EmployeeID                           :
EmployeeNumber                       :
Enabled                              : True
Fax                                  :
GivenName                            :
HomeDirectory                        :
HomedirRequired                      : False
HomeDrive                            :
HomePage                             :
HomePhone                            :
Initials                             :
instanceType                         : 4
isDeleted                            :
KerberosEncryptionType               : {}
LastBadPasswordAttempt               :
LastKnownParent                      :
lastLogoff                           : 0
lastLogon                            : 0
LastLogonDate                        :
LockedOut                            : False
logonCount                           : 0
LogonWorkstations                    :
Manager                              :
MemberOf                             : {}
MNSLogonAccount                      : False
MobilePhone                          :
Modified                             : 18/11/2016 11:03:02
modifyTimeStamp                      : 18/11/2016 11:03:02
msDS-User-Account-Control-Computed   : 8388608
Name                                 : FOX Fred
nTSecurityDescriptor                 : System.DirectoryServices.ActiveDirectorySecurity
ObjectCategory                       : CN=Person,CN=Schema,CN=Configuration,DC=Manticore,DC=org
ObjectClass                          : user
ObjectGUID                           : db5a3975-980d-4749-b9c0-48aff9217b2a
objectSid                            : S-1-5-21-759617655-3516038109-1479587680-1314
Office                               :
OfficePhone                          :
Organization                         :
OtherName                            :
PasswordExpired                      : True
PasswordLastSet                      : 17/11/2016 14:07:13
PasswordNeverExpires                 : False
PasswordNotRequired                  : False
POBox                                :
PostalCode                           :
PrimaryGroup                         : CN=Domain Users,CN=Users,DC=Manticore,DC=org
primaryGroupID                       : 513
PrincipalsAllowedToDelegateToAccount : {}
ProfilePath                          :
ProtectedFromAccidentalDeletion      : False
pwdLastSet                           : 131238652330182673
SamAccountName                       : foxfred
sAMAccountType                       : 805306368
ScriptPath                           :
sDRightsEffective                    : 15
ServicePrincipalNames                : {}
SID                                  : S-1-5-21-759617655-3516038109-1479587680-1314
SIDHistory                           : {}
SmartcardLogonRequired               : False
State                                :
StreetAddress                        :
Surname                              :
Title                                :
TrustedForDelegation                 : False
TrustedToAuthForDelegation           : False
UseDESKeyOnly                        : False
userAccountControl                   : 512
userCertificate                      : {}
UserPrincipalName                    : FredFox@manticore.org
uSNChanged                           : 78123
uSNCreated                           : 62259
whenChanged                          : 18/11/2016 11:03:02
whenCreated                          : 17/11/2016 14:07:13

Using –properties * returns ALL of the properties of a user. That’s OK if you’re looking at one, or a few users, but becomes a very expensive operation if you’re looking at thousands of user objects.

A more elegant approach is to specify the properties you want:

PS> Get-ADUser -Identity foxfred -Properties EmailAddress, LockedOut, ProtectedFromAccidentalDeletion, whenCreated

DistinguishedName               : CN=FOX Fred,OU=UserAccounts,DC=Manticore,DC=org
EmailAddress                    :
Enabled                         : True
GivenName                       :
LockedOut                       : False
Name                            : FOX Fred
ObjectClass                     : user
ObjectGUID                      : db5a3975-980d-4749-b9c0-48aff9217b2a
ProtectedFromAccidentalDeletion : False
SamAccountName                  : foxfred
SID                             : S-1-5-21-759617655-3516038109-1479587680-1314
Surname                         :
UserPrincipalName               : FredFox@manticore.org
whenCreated                     : 17/11/2016 14:07:13

You get the properties you specified and the default properties.

So, while Get-ADUser doesn’t display all properties you can overcome this by using the –properties parameter with a * for all properties or a list of the properties you want in addition to the defaults.

Posted in PowerShell and Active Directory | 1 Comment

Filtering of Objects and Properties

Saw a post on the forum today that suggests people are still confused about how to perform filtering of objects and properties in PowerShell.

As with so much in PowerShell explanations are always better with examples.

Let’s start with the physical disks in a computer:

PS> Get-PhysicalDisk

FriendlyName               SerialNumber    CanPool OperationalStatus HealthStatus Usage            Size
------------               ------------    ------- ----------------- ------------ -----            ----
Toshiba USB 2.0 Ext. HDD   WD-WCAMR3209671 False   OK                Healthy      Auto-Select 298.09 GB
ST916082 1A                DEF10E8D9B36    False   OK                Healthy      Auto-Select 149.05 GB
Samsung SSD 840 PRO Series S1AXNSAF329511V False   OK                Healthy      Auto-Select 476.94 GB

If you want to objects that match a specific criteria – for instance disk is larger than 300GB:

PS> Get-PhysicalDisk | Where-Object Size -gt 300GB

FriendlyName               SerialNumber    CanPool OperationalStatus HealthStatus Usage            Size
------------               ------------    ------- ----------------- ------------ -----            ----
Samsung SSD 840 PRO Series S1AXNSAF329511V False   OK                Healthy      Auto-Select 476.94 GB

Where-Object is your friend.

What you’re actually doing – though very few people actually write it like this – is

Get-PhysicalDisk | Where-Object -Property Size -GT -Value 300GB

The help file for Where-Object lists the possible operators.

You can also show the original style syntax

Get-PhysicalDisk | Where-Object -FilterScript {$_.Size -gt 300GB}

Normal usage is to not write the –FilterScript parameter so it becomes

Get-PhysicalDisk | Where-Object {$_.Size -gt 300GB}

$_ represents the object currently on the pipeline. If you need to use multiply conditions in your filter you’ll need to use the older style syntax.

So far you’ve seen how reduce the number of objects on the pipeline. Where-Object filters out those that don’t match the given criteria.

If you want to reduce the number of properties that the objects on the pipeline possess you’ll need to use Select-Object

PS> Get-PhysicalDisk | Select-Object -Property FriendlyName, HealthStatus, Size

FriendlyName               HealthStatus         Size
------------               ------------         ----
Toshiba USB 2.0 Ext. HDD   Healthy      320072933376
ST916082 1A                Healthy      160041885696
Samsung SSD 840 PRO Series Healthy      512110190592

More commonly written as

Get-PhysicalDisk | Select FriendlyName, HealthStatus, Size

PowerShell best practice is always to use the full cmdlet and parameter names in your scripts. The *-Object cmdlets and in particular Where-Object, Sort-Object and Select-Object are often abbreviated to Where, Sort and Select and the parameters only used where necessary.  This was the way I was advised to use them by Jeffrey Snover – who invented PowerShell –  when I wrote PowerShell in Practice. Good enough for me.

Posted in Powershell Basics | Leave a comment

PowerShell Summit 2017 – – more seats available

After selling out in record time we’ve managed to squeeze a few more seats in after discussion with the conference centre.

Those seats are live now.

They are very definitely, the absolute last set of seats we’ll be able to add this year.

First come – First served. When they’re gone – they’re gone

Posted in Powershell, Summit | Leave a comment

PowerShell Summit 2017–sold out

We sold the last seat for the 2017 Summit – https://eventloom.com/event/home/summit2017 yesterday.

If, and its a very big if, more seats become available we’ll notify you though the event web site and on powershell.org

Posted in Powershell, Summit | Leave a comment