January 2012 - Posts

Reading direct reports

As stated last time the direct reports is a backlink created from the users who have this particular user as a manager

Displaying this attribute is straight forward

if (-not (Get-Module ActiveDirectory)){            
  Import-Module ActiveDirectory            
}            
            
$ou = "OU=England,DC=Manticore,DC=org"            
$manager = "CN=HORNBLOWER Horatio,$ou"            
            
"`nMicrosoft"            
Get-ADUser -Identity $manager -Properties * |             
select -ExpandProperty directReports            
            
            
"`nAD provider"            
Get-ItemProperty -Path AD:\$manager  -Name directReports |             
select -ExpandProperty directReports            
             
"`nQuest"            
Get-QADUser -Identity $manager -IncludeAllProperties |             
select -ExpandProperty directReports            
            
            
"`nScript"            
$user = [adsi]"LDAP://$manager"            
$user |             
select -ExpandProperty directReports

No real surprises – get the user and display the property. Its a collection so using –ExpandProperty is the easiest way to display

User organisation details

The organization tab on the user properties can hold a number of items – job title, department, company, manager & direct reports

The first four we can set directly. The direct reports attribute is a backlink meaning it is filled with the distinguished names of the users who have  a particular user set as their manager.

The properties we can set are managed like this

if (-not (Get-Module ActiveDirectory)){            
  Import-Module ActiveDirectory            
}            
            
$ou = "OU=England,DC=Manticore,DC=org"            
            
$dept = "Secret Squirrel stuff"            
$comp = "Hush Hush Co Ltd"            
$manager = "CN=HORNBLOWER Horatio,$ou"            
            
"`nMicrosoft"            
$name = "UserA"            
$title = "VP for stuff"            
Get-ADUser -Identity $name |            
Set-ADUser -Title $title -Department $dept -Company $comp -Manager $manager            
            
"`nAD provider"            
$name = "UserB"            
$title = "VP for something or other"            
$dn = "cn=$name,$ou"            
Set-ItemProperty -Path AD:\$dn  -Name title      -Value $title   -Force            
Set-ItemProperty -Path AD:\$dn  -Name department -Value $dept    -Force            
Set-ItemProperty -Path AD:\$dn  -Name company    -Value $comp    -Force            
Set-ItemProperty -Path AD:\$dn  -Name manager    -Value $manager -Force            
             
"`nQuest"            
$name = "UserC"            
$title = "VP for things"            
Get-QADUser -Identity $name |            
Set-QADUser -Title $title -Department $dept -Company $comp -Manager $manager            
            
"`nScript"            
$name = "UserD"            
$title = "VP for other things"            
$dn = "cn=$name,$ou"            
$user = [adsi]"LDAP://$dn"            
$user.title = $title            
$user.department = $dept            
$user.company = $comp            
$user.manager = $manager            
$user.SetInfo()

 

The cmdlets have parameters for each attribute while the provider and script have to work a bit harder

Naming Contexts

Continuing our quick look at The ActiveDirectory name space lets have a look at the MSAD_NamingContext  class

Get-WmiObject -Namespace root\MicrosoftActiveDirectory -Class MSAD_NamingContext |

Format-Table DistinguishedName, IsFullReplica –AutoSize

 

DistinguishedName                              IsFullReplica
-----------------                              -------------
DC=DomainDnsZones,DC=Manticore,DC=org                   True
DC=ForestDnsZones,DC=Manticore,DC=org                   True
CN=Schema,CN=Configuration,DC=Manticore,DC=org          True
CN=Configuration,DC=Manticore,DC=org                    True
DC=Manticore,DC=org                                     True

 

This is equivalent to the information you see in the root of the AD provider

PS> Get-ChildItem -Path AD:\

Name                 ObjectClass          DistinguishedName
----                 -----------          -----------------
Manticore            domainDNS            DC=Manticore,DC=org
Configuration        configuration        CN=Configuration,DC=Manticore,DC=org
Schema               dMD                  CN=Schema,CN=Configuration,DC=Manticore,DC=org
ForestDnsZones       domainDNS            DC=ForestDnsZones,DC=Manticore,DC=org
DomainDnsZones       domainDNS            DC=DomainDnsZones,DC=Manticore,DC=org

Active Directory and WMI

A lot of the Active Directory related functionality has been removed from WMI but  there is a little bit left in the root\MicrosoftActiveDirectory namespace.

This is on a Windows 2008 R2 domain controller – I don’t know if this is available on down level versions of Windows.

Get-WmiObject -Namespace root\MicrosoftActiveDirectory -List | where {$_.Name -notlike "__*"}

 

ReplicationProvider1
MSAD_ReplPendingOp
Microsoft_TrustProvider
Microsoft_DomainTrustStatus
Microsoft_LocalDomainInfo
MSAD_NamingContext
MSAD_ReplCursor
MSAD_DomainController
MSAD_ReplNeighbor

The mixture of naming conventions doesn’t help but lets start looking at some domain information

Get-WmiObject -Namespace root\MicrosoftActiveDirectory -Class Microsoft_LocalDomainInfo

 

The following properties of interest are returned

DCname           : SERVER02
DNSname          : Manticore.org
FlatName         : MANTICORE
SID              : S-1-5-21-3881460461-1879668979-35955009
TreeName         : Manticore.org

 

We can also get a quick replication test

 

Get-WmiObject -Namespace root\MicrosoftActiveDirectory -Class MSAD_DomainController |
select CommonName, DistinguishedName, IsAdvertisingToLocator, IsGC, IsNextRIDPoolAvailable,
IsRegisteredInDNS, IsSysVolReady, NTDsaGUID, PercentOfRIDsLeft, SiteName,
@{N="OldestQueuedAddition"; E={$_.ConvertToDateTime($_.TimeOfOldestReplAdd)} },
@{N="OldestQueuedDeletion"; E={$_.ConvertToDateTime($_.TimeOfOldestReplDel)} },
@{N="OldestQueuedModification"; E={$_.ConvertToDateTime($_.TimeOfOldestReplMod)} },
@{N="OldestQueuedReplicationSync"; E={$_.ConvertToDateTime($_.TimeOfOldestReplSync)} },
@{N="OldestQueuedReplicationUpdate"; E={$_.ConvertToDateTime($_.TimeOfOldestReplUpdRefs)} }

 

CommonName                    : SERVER02
DistinguishedName             : CN=NTDS Settings,CN=SERVER02,CN=Servers,CN=Site1,CN=Sites,CN=Configuration,DC=Manticore,DC=org
IsAdvertisingToLocator        : True
IsGC                          : True
IsNextRIDPoolAvailable        : False
IsRegisteredInDNS             : True
IsSysVolReady                 : True
NTDsaGUID                     : baba1150-8a6a-41ac-9889-4b69268d3f7c
PercentOfRIDsLeft             : 91
SiteName                      : Site1
OldestQueuedAddition          : 01/01/1601 00:00:00
OldestQueuedDeletion          : 01/01/1601 00:00:00
OldestQueuedModification      : 01/01/1601 00:00:00
OldestQueuedReplicationSync   : 01/01/1601 00:00:00
OldestQueuedReplicationUpdate : 01/01/1601 00:00:00

 

The 1601 dates mean nothing is queued

Setting user address information

In AD Users & Computers the user’s properties dialog has a tab for setting address information

 

if (-not (Get-Module ActiveDirectory)){            
  Import-Module ActiveDirectory            
}            
            
$ou = "OU=England,DC=Manticore,DC=org"            
$street = @"
123 Somewhere Place, 
A big suburb
"@             
            
$PObox = "PO 456"            
$city = "Salisbury"            
$state = "Wiltshire"            
$zip = "SY27 5QW"            
$country = "GB"            
            
"`nMicrosoft"            
$name = "UserA"            
Get-ADUser -Identity $name |            
Set-ADUser -StreetAddress $street -POBox $PObox -City $city -State $state -PostalCode $zip -Country $country            
            
"`nAD provider"            
$name = "UserB"            
$dn = "cn=$name,$ou"            
Set-ItemProperty -Path AD:\$dn  -Name streetAddress -Value $street  -Force            
Set-ItemProperty -Path AD:\$dn  -Name postOfficeBox -Value $POBox   -Force            
Set-ItemProperty -Path AD:\$dn  -Name l             -Value $city    -Force            
Set-ItemProperty -Path AD:\$dn  -Name st            -Value $state   -Force            
Set-ItemProperty -Path AD:\$dn  -Name postalCode    -Value $zip     -Force            
Set-ItemProperty -Path AD:\$dn  -Name c             -Value $country -Force            
             
"`nQuest"            
$name = "UserC"            
Get-QADUser -Identity $name |            
Set-QADUser -StreetAddress $street -PostOfficeBox $PObox -City $city -StateOrProvince $state -PostalCode $zip -ObjectAttributes @{c=$country}            
            
"`nScript"            
$name = "UserD"            
$dn = "cn=$name,$ou"            
$user = [adsi]"LDAP://$dn"            
$user.streetAddress = $street            
$user.postOfficeBox = $PObox            
$user.l = $city            
$user.st = $state            
$user.postalCode = $zip            
$user.c = $country            
$user.SetInfo()

To keep everything consistent I’ve set the address information as a set of variables. The street address is a here-string so we can get multiple lines into the address. The country is designated by the 2 letter ISO code – be careful with this. I tend to set in the GUI and then check the property value in ADSIEdit if I have any doubts.

This is a totally made up address

The Microsoft cmdlet has a parameter for each element of the address. The Quest cmdlet is the same except, bizarrely, the country

The provider and script we have to set each property. Notice that some properties are not intuitive:

  • l = city
  • st = state
  • c = country

PowerShell Deep Dive 2012

The 2012 PowerShell Deep Dive has been announced  - April 29 – May 2 in San Diego.

http://blogs.msdn.com/b/powershell/archive/2012/01/27/it-s-time-for-another-powershell-deep-dive.aspx

 

This time PowerShell is a full track so expect more of your favourite stuff.  Hope to see you there.

Posted by RichardSiddaway | 1 comment(s)
Filed under: ,

Restricting a user’s computers

On the Account tab of an AD user’s properties there is a button labelled “Logon to …” that can be used to restrict the computers a user can logon onto. The default is that users can log onto any machine. If you want to script the restriction

if (-not (Get-Module ActiveDirectory)){            
  Import-Module ActiveDirectory            
}            
            
$ou = "OU=England,DC=Manticore,DC=org"            
$ws = "Comp1,Comp2,Comp3,Comp4,Comp5"            
            
"`nMicrosoft"            
$name = "UserA"            
Get-ADUser -Identity $name |            
Set-ADUser -Replace @{userWorkstations = $ws}            
            
"`nAD provider"            
$name = "UserB"            
$dn = "cn=$name,$ou"            
Set-ItemProperty -Path AD:\$dn  -Name userWorkstations -Value $ws -Force            
            
"`nQuest"            
$name = "UserC"            
Get-QADUser -Identity $name |            
Set-QADUser -ObjectAttributes @{userWorkstations = $ws}            
#>            
"`nScript"            
$name = "UserD"            
$dn = "cn=$name,$ou"            
$user = [adsi]"LDAP://$dn"            
$user.userWorkstations = $ws            
$user.SetInfo()

Create a list on computer names – notice that there aren’t any spaces between the computer names – this is required.

Otherwise the scripts work in the same way as setting any other property

Integer sizes

 

If you’ve used PowerShell for any time you will be away of [int] meaning integer. One common use is in functions to define a parameter’s data type

function test1 {
param (
  [int]$a,
  [int]$b
)
$a * $b
}

We can use this function

PS> test1 -a 10 -b 6
60

OK simple stuff but what if we do this

PS> test1 -a 2147483648 -b 17
test1 : Cannot process argument transformation on parameter 'a'. Cannot convert
value "2147483648" to type "System.Int32". Error: "Value was either too large
or too small for an Int32."
At line:1 char:9
+ test1 -a <<<<  2147483648 -b 17
    + CategoryInfo          : InvalidData: (:) [test1], ParameterBindin...mati
   onException
    + FullyQualifiedErrorId : ParameterArgumentTransformationError,test1

Oh

Integers come in a number of different sizes – denoted by the number of bits that are used to store the number – 16, 32 and 64 respectively.  The standard [int] is a 32bit integer (4 bytes)

We can see the maximum and minimum numbers that can be stored in these data types using the MaxValue and MinValue properties

"`n16 bit integer"
"$([int16]::MinValue) to $([int16]::MaxValue)"

"`n32 bit integer"
"$([int32]::MinValue) to $([int32]::MaxValue)"

"`n32 bit integer alternative"
"$([int]::MinValue) to $([int]::MaxValue)"

"`n64 bit integer"
"$([int64]::MinValue) to $([int64]::MaxValue)"

 

which gives these results

16 bit integer
-32768 to 32767

32 bit integer
-2147483648 to 2147483647

32 bit integer alternative
-2147483648 to 2147483647

64 bit integer
-9223372036854775808 to 9223372036854775807

 

So 2147483648 is one bigger than the maximum value storable in 32 bit integer. We could use a 64bit integer or we can use an unsigned integer. This only contains positive values

"`nunsigned 16 bit integer"
"$([uint16]::MinValue) to $([uint16]::MaxValue)"

"`nunsigned 32 bit integer"
"$([uint32]::MinValue) to $([uint32]::MaxValue)"

"`nunsigned 64 bit integer"
"$([uint64]::MinValue) to $([uint64]::MaxValue)"

 

unsigned 16 bit integer
0 to 65535

unsigned 32 bit integer
0 to 4294967295

unsigned 64 bit integer
0 to 18446744073709551615

Which should you use?  Use int64 if likely to have negative values and possibly uint32 if definitely only positive values

Posted by RichardSiddaway | with no comments
Filed under:

Setting a users logon hours

By default a user can logon 24/7.  Is this acceptable – should users be able to logon during the night or weekends. AD Users and Computers has a GUI to set the hours users can logon. But we don’t need a GUI we can do this

if (-not (Get-Module ActiveDirectory)){            
  Import-Module ActiveDirectory            
}            
            
$ou = "OU=England,DC=Manticore,DC=org"            
            
## allow logon 8am - 6pm Monday to Friday            
[byte[]]$hours = @(0,0,0,0,255,3,0,255,3,0,255,3,0,255,3,0,255,3,0,0,0)            
            
"`nMicrosoft"            
$name = "UserA"            
Get-ADUser -Identity $name |            
Set-ADUser -Replace @{logonhours = $hours}            
            
"`nAD provider"            
$name = "UserB"            
$dn = "cn=$name,$ou"            
Set-ItemProperty -Path AD:\$dn  -Name logonhours -Value $hours -Force            
            
"`nQuest"            
$name = "UserC"            
Get-QADUser -Identity $name |            
Set-QADUser -ObjectAttributes @{logonhours = $hours}            
            
"`nScript"            
$name = "UserD"            
$dn = "cn=$name,$ou"            
$user = [adsi]"LDAP://$dn"            
$user.logonhours[0] = $hours            
$user.SetInfo()

We’ll use the four test users we created earlier in the England OU.

The important point is how we represent the hours users can logon.

The information is stored as a byte array – 3bytes per day with 1 bit per hour

We want to restrict the users to 8am-6pm Monday to Friday so we use

[byte[]]$hours = @(0,0,0,0,255,3,0,255,3,0,255,3,0,255,3,0,255,3,0,0,0)

Sunday is the start of the week – no logons allowed so first three bytes are 0. Monday’s three bytes starts with a 0 as don’t want logons between midnight and 8am. The 8 hours of logons followed by two hours. etc

A few other examples might help

Deny all logon

[byte[]]$hours = @(0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0)

 

Allow logon at all hours

[byte[]]$hours = @(255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255)

 

Allow 8am-6pm – 7 days a week

[byte[]]$hours = @(0,255,3,0,255,3,0,255,3,0,255,3,0,255,3,0,255,3,0,255,3)

 

If you are in doubt about generating the array – set in the GUI then copy the values using ADSIEdit

The scripts are straightforward – the cmdlets get the user and pipe to set. The difference is the parameter we use

The provider uses Set-Itemproperty and the only oddity in the script is we use logonhours[0] as the property. This forces acceptance of the byte array

Creating an OU

Creating an OU is a fairly common activity. The GUI is quick enough for a single OU but we need PowerShell for bulk creation.

Its a straight forward activity

if (-not (Get-Module ActiveDirectory)){            
  Import-Module ActiveDirectory            
}            
            
$ou = "OU=BlogTests,DC=Manticore,DC=org"            
            
"`nMicrosoft"            
$name = "OUM"            
New-ADOrganizationalUnit -Path $ou -Name $name            
            
"`nAD provider"            
$name = "OUP"            
New-Item -Path AD:\$ou -Name "OU=$name" -ItemType Directory            
            
"`nQuest"            
$name = "OUQ"            
New-QADObject -ParentContainer $ou -Type 'OrganizationalUnit' -NamingProperty 'ou' -Name $name            
            
"`nScript"            
$name = "OUS"            
$target = [adsi]"LDAP://$ou"            
$user = $target.Create("organizationalunit", "ou=$name")            
$user.SetInfo()

There is a Microsoft cmdlet specifically for this activity. Just give it a path and a name.  The Quest cmdlet is marginally more complicated but still easy.

The script you will recognise as a variant of creating a user. This pattern works for most things in ADSI – get the parent container and use the Create() method.

The provide uses New-Item as you would expect – notice the ItemType is Directory!

Alternatively the provider supplies the ultimate shortcut code for creating an OU.  Yes md (or mkdir) work

cd ad:\$ou
md "ou=testing"

Finding a users group membership

Continuing our look at users – do we know what groups they are in?

if (-not (Get-Module ActiveDirectory)){            
  Import-Module ActiveDirectory            
}            
            
"`nMicrosoft"            
Get-ADUser -Identity Richard -Properties * |             
select -ExpandProperty memberOf            
            
            
"`nAD provider"            
$dn = "CN=Richard,CN=Users,DC=Manticore,DC=org"            
Get-ItemProperty -Path AD:\$dn -Name memberof |             
select -ExpandProperty memberof            
            
"`nQuest"            
Get-QADUser -Identity Richard |             
Get-QADMemberOf |             
select name, Description            
            
"`nScript"            
$root = [ADSI]""            
$search = [adsisearcher]$root            
$search.Filter = "(&(objectclass=user)(objectcategory=user)(cn=Richard))"            
$search.SizeLimit = 3000            
$results = $search.FindOne()            
            
foreach ($result in $results){            
    $result.Properties.memberof             
}

The Microsoft cmdlet, AD provider and script are similar in that we get an object representing the user and read the memberof property. This is a backlink property that maintains a list of the distinguished names of the groups in which the user has membership. Every time you add or remove a user from a group this property will be automatically updated.

The Quest cmdlets give us the option of working like the Microsoft cmdlet or we can pipe into Get-QADMemberof which gives a few options for a better display.

Remoting between PowerShell v3 CTP 2 and PowerShell v2

One of the questions on tonight’s Live Meeting concerned the compatibility between remoting on PowerShell v2 and PowerShell v3 CTP 2

The difference is that v3 uses a WSMAN 3.0 stack but v2 uses 2.0

I used two machines:

  • Windows 2008 R2 SP 1 with PowerShell v2
  • Windows 7 SP1 with PowerShell v3 CTP 2

 

on each machine I ensured remoting was enabled then ran

$s = New-PSSession –ComputerName <other computer name>
Invoke-Command -Session $s -ScriptBlock {get-service}

 

it worked in both cases

Looks like in this case you can remote both ways

Recording–UK PowerShell group January 2012

The recording of tonight’s meeting together with the slides and demo scripts are available from

https://skydrive.live.com/?cid=43cfa46a74cf3e96#cid=43CFA46A74CF3E96&id=43CFA46A74CF3E96%212469&sc=documents

 

download the zip file from the 2012 January PowerShell v3 CTP2 overview folder

 

Enjoy

Get-CimClass

Get-CimClass is used to dig into the information available within a WMI class.

At its most basic level we get a set of information like this

PS> Get-CimClass -ClassName Win32_OperatingSystem | fl *


ClassName           : Win32_OperatingSystem
SuperClassName      : CIM_OperatingSystem
CimSuperClassName   : CIM_OperatingSystem
SuperClass          : Microsoft.Management.Infrastructure.CimClass
CimSuperClass       : Microsoft.Management.Infrastructure.CimClass
Namespace           : ROOT/cimv2
Properties          : {Caption, Description, InstallDate, Name...}
CimClassProperties  : {Caption, Description, InstallDate, Name...}
Qualifiers          : {Locale, UUID, dynamic, provider...}
CimClassQualifiers  : {Locale, UUID, dynamic, provider...}
Methods             : {Reboot, Shutdown, Win32Shutdown, Win32ShutdownTracker...}
CimClassMethods     : {Reboot, Shutdown, Win32Shutdown, Win32ShutdownTracker...}
CimSystemProperties : Microsoft.Management.Infrastructure.CimSystemProperties

 

We get a few parameters to work with

PS> Get-Help Get-CimClass

NAME
    Get-CimClass

SYNTAX
    Get-CimClass [[-ClassName] <string>] [[-Namespace] <string>] [-OperationTimeoutSec <UInt32>] [-ComputerName
    <string[]>] [-MethodName <string>] [-PropertyName <string>] [-QualifierName <string>]  [<CommonParameters>]

    Get-CimClass [[-ClassName] <string>] [[-Namespace] <string>] [-OperationTimeoutSec <UInt32>] -CimSession
    <CimSession[]> [-MethodName <string>] [-PropertyName <string>] [-QualifierName <string>]  [<CommonParameters>]

 

Want to know which WMI classes have a method called create

PS> Get-CimClass -MethodName Create


   NameSpace: ROOT/cimv2

ClassName                 Methods              Properties
---------                 -------              ----------
Win32_ShadowStorage       {Create}             {AllocatedSpace, DiffVolume, MaxSpace, UsedSpace...}
Win32_ScheduledJob        {Create, Delete}     {Caption, Description, InstallDate, Name...}
Win32_DfsNode             {Create}             {Caption, Description, InstallDate, Name...}
Win32_BaseService         {StartService, St... {Caption, Description, InstallDate, Name...}
Win32_SystemDriver        {StartService, St... {Caption, Description, InstallDate, Name...}
Win32_Service             {StartService, St... {Caption, Description, InstallDate, Name...}
Win32_TerminalService     {StartService, St... {Caption, Description, InstallDate, Name...}
Win32_Share               {Create, SetShare... {Caption, Description, InstallDate, Name...}
Win32_ClusterShare        {Create, SetShare... {Caption, Description, InstallDate, Name...}
Win32_ShadowCopy          {Create, Revert}     {Caption, Description, InstallDate, Name...}
Win32_Process             {Create, Terminat... {Caption, Description, InstallDate, Name...}

 

or a property called Size

PS> Get-CimClass -PropertyName Size


   NameSpace: ROOT/cimv2

ClassName
---------
Win32_DiskDrive
Win32_CDROMDrive
CIM_LogicalDisk
Win32_LogicalDisk
Win32_MappedLogicalDisk
Win32_DiskPartition
Win32_PrintJob

We can dig deeper into a class

Get-CimClass -ClassName Win32_OperatingSystem | select -ExpandProperty Properties

provides an output like this for every property

Name               : CSName
Value              :
CimType            : String
Flags              : Property, ReadOnly, NullValue
Qualifiers         : {CIM_Key, MaxLen, Propagated, read}
ReferenceClassName :

 

Likewise methods

Get-CimClass -ClassName Win32_OperatingSystem | select -ExpandProperty Methods

 

or if you want detail on a particular method

PS> Get-CimClass -ClassName Win32_OperatingSystem | select -ExpandProperty Methods | where name -eq SetDateTime | fl *


Name       : SetDateTime
ReturnType : UInt32
Parameters : {LocalDateTime}
Qualifiers : {Implemented, Privileges, ValueMap}

 

And no thats not a typo on the where statement – its a new PowerShell v3 feature I’ll cover another day

Get-CimClass -ClassName Win32_OperatingSystem  | select -ExpandProperty Qualifiers

and

Get-CimClass -ClassName Win32_OperatingSystem  | select -ExpandProperty CimSystemProperties | fl *

do what you would expect

Finding the key property for a class is a useful exercise

Get-CimClass -ClassName Win32_Process | select -ExpandProperty Properties | where {$_.Qualifiers -like "*key*"}

returns a number of properties – some are like this

Name               : CreationClassName
Value              :
CimType            : String
Flags              : Property, ReadOnly, NullValue
Qualifiers         : {CIM_Key, MaxLen, read}
ReferenceClassName :

 

and have the CIM_Key qualifier but the one we are really interested in is this one

Name               : Handle
Value              :
CimType            : String
Flags              : Property, Key, ReadOnly, NullValue
Qualifiers         : {key, MaxLen, read}
ReferenceClassName :

 

Lots of useful information to be gained from this cmdlet. Don’t leave home to explore WMI without it.

January meeting reminder

Just a quick reminder that on Tuesday 24 January the UK PowerShell Group presents a Live Meeting looking at PowerShell v3 CTP2

 

Details from here

http://msmvps.com/blogs/richardsiddaway/archive/2012/01/02/uk-powershell-group-january-2012.aspx

Get the domain distinguished name

A comment on my post about finding domain controllers

http://msmvps.com/blogs/richardsiddaway/archive/2012/01/21/1805130.aspx

asked about finding the OU as its always seemed to be hard coded into these scripts.

The reason for the hard coding is to keep down  the script size so that its easier to absorb and we are only concentrating on the working bits of the script. 

Creating some of the OUs in scripts is very possible – but only the ones you know about. For instance all domains have:

  • a Domain Controllers OU
  • a Users container
  • a Computers container

Some of my examples have an England OU – which you might not have. Or you might nested OUs.

We can look at getting the distinguished name of the  Domain  Controllers OU an example

if (-not (Get-Module ActiveDirectory)){            
  Import-Module ActiveDirectory            
}            
            
"`nMicrosoft"            
$domdn = Get-ADDomain | select -ExpandProperty DistinguishedName            
$domdn            
$dcOU = Get-ADDomain | select -ExpandProperty DomainControllersContainer            
$dcOU            
            
"`nAD provider"            
$dom = Get-ChildItem -Path Ad:\ | where {$_.Name -eq "Configuration"}            
$domdn = ($dom.DistinguishedName -split "," ,2)[1]            
$domdn             
            
$dcOU = "OU=Domain Controllers,$domdn"            
$dcOU            
            
"`nQuest"            
$domdn = Get-QADRootDSE | select -ExpandProperty RootDomainNamingContext            
$domdn             
            
$dcOU = "OU=Domain Controllers,$domdn"            
$dcOU            
            
"`nScript"            
$domain = [System.DirectoryServices.ActiveDirectory.Domain]::GetCurrentDomain()            
$domdn = $domain.GetDirectoryEntry() | select -ExpandProperty DistinguishedName            
$domdn             
            
$dcOU = "OU=Domain Controllers,$domdn"            
$dcOU

I get results like this

Microsoft
DC=Manticore,DC=org
OU=Domain Controllers,DC=Manticore,DC=org

AD provider
DC=Manticore,DC=org
OU=Domain Controllers,DC=Manticore,DC=org

Quest
DC=Manticore,DC=org
OU=Domain Controllers,DC=Manticore,DC=org

Script
DC=Manticore,DC=org
OU=Domain Controllers,DC=Manticore,DC=org

 

The important part is how we get the root of the domain.  Each of the techniques is different but we get to the same result.

You do this as alternative for the script method

$dom = [adsi]""
$domdn = $dom.distinguishedName

$dcOU = “OU=Domain Controllers,$domdn”

SMART disk failure data

We can access the SMART disk failure data using

Get-WmiObject -Namespace root\wmi -Class MSStorageDriver_FailurePredictData

 

The important properties are:

Active           : True
InstanceName     : IDE\DiskST9250320AS_____________________________HP07____\5&b0fd174&0&1.0.0_0
Length           : 512
VendorSpecific   : {10, 0, 1, 15...}

 

The data we want is in the VendorSpecific property. On my system its an array of 512 numbers – not very useful but we can (hopefully) decode this

function get-diskstatus {            
[CmdletBinding()]            
param (            
 [string]$computername = $env:COMPUTERNAME            
)            
            
$items = "Unknown1","Unknown2", "Attribute", "Status", "Unknown3", "Value", "Worst", "Raw1", "Raw2", "Unknown4","Unknown5","Unknown6"            
            
$data = Get-WmiObject -Namespace root\wmi -Class MSStorageDriver_FailurePredictData -ComputerName $computername             
            
#$data | select InstanceName, Active            
            
$values = $data.VendorSpecific            
$flb =  $values.Count - ($values.Count % 12) -1            
            
for ($i = 0; $i -le $flb-11; $i += 12  ){            
            
$obj = New-Object -TypeName PSObject            
            
for($j = 0; $j -le 11; $j++) {             
$obj | Add-Member -MemberType Noteproperty -Name $($items[$j]) -Value $($values[$i + $j])            
}            
$obj            
}            
}            

 

We can use this as

get-diskstatus | ft * –a

 

I only have a single disk in my system so this works – I’ll need to modify the function to deal with multiple disks

 

But this is what I get back

 

Unknown1 Unknown2 Attribute Status Unknown3 Value Worst Raw1 Raw2 Unknown4 Unknown5 Unknown6
-------- -------- --------- ------ -------- ----- ----- ---- ---- -------- -------- --------
      10        0         1     15        0   114    99   62  168       88        4        0
       0        0         3      2        0    99    99    0    0        0        0        0
       0        0         4     51        0    99    99   95    5        0        0        0
       0        0         5     51        0   100   100   17    0        0        0        0
       0        0         7     15        0    81    60  227   94      126        8        0
       0        0         9     50        0    90    90  132   34        0        0        0
       0        0        10     19        0   100   100    0    0        0        0        0
       0        0        12     51        0    99    99  248    4        0        0        0
       0        0       184     51        0   100   100    0    0        0        0        0
       0        0       187     50        0   100   100    0    0        0        0        0
       0        0       188     50        0   100    99   11    0        0        0        0
       0        0       189     58        0   100   100    0    0        0        0        0
       0        0       190     34        0    56    51   44    0       20       45        0
       0        0       191     50        0   100   100   54    0        0        0        0
       0        0       192     50        0   100   100    0    0        0        0        0
       0        0       193     50        0    96    96  166   34        0        0        0
       0        0       194     34        0    44    49   44    0        0        0       16
       0        0       195     26        0    51    49   62  168       88        4        0
       0        0       196     51        0   100   100   17    0        0        0        0
       0        0       197     18        0   100   100    0    0        0        0        0
       0        0       198     16        0   100   100    0    0        0        0        0
       0        0       199     62        0   200   200    0    0        0        0        0
       0        0       254     50        0   100   100    0    0        0        0        0
       0        0         0      0        0     0     0    0    0        0        0        0
       0        0         0      0        0     0     0    0    0        0        0        0
       0        0         0      0        0     0     0    0    0        0        0        0
       0        0         0      0        0     0     0    0    0        0        0        0
       0        0         0      0        0     0     0    0    0        0        0        0
       0        0         0      0        0     0     0    0    0        0        0        0
       0        0         0      0        0     0     0    0    0        0        0        0
       0        0         0      0      200     2     0  115    3        0        1        0
       2       92         3      0        0     0     0    0    0        0        0        0
       0        0         0      0        0     0     0    0    4        1        1        1
       1        1         1      1        1     0     0    0    0        0        0        0
       0        1         0      0        0     0     0    0    0        0        0        0
      54        0         0      0       33   186   100  101  238       28        0        0
       0        0         0      0        1     0   189    1  172      221      133      205
      35        0         0      0      154    12   230  180  219        1        0        0
       0        0         0      0        0   187    32    0    0        0        0        0
       0        0         0      0      105    36     0    0    0        0        0        0
       0        0         0      0        0     0     0    0    0        0        0        0
       0        0         0      0        0     0     0    0    0        0        0        0

 

Next job is to decode some of this information

Posted by RichardSiddaway | with no comments
Filed under:

SMART disks

A question on the forum about using WMI to work with SMART disks got my digging into the subject.  SMART disks - http://en.wikipedia.org/wiki/S.M.A.R.T – detect and report on disk problems (hopefully) before they cause a catastrophe. While vendors’ implementations vary there are some things we can access.

The WMI classes are in the root\wmi namespace

PS> Get-WmiObject -Namespace root\wmi -List MSStorageDriver_Failure* | select Name

Name
----
MSStorageDriver_FailurePredictEvent
MSStorageDriver_FailurePredictFunction
MSStorageDriver_FailurePredictData
MSStorageDriver_FailurePredictThresholds
MSStorageDriver_FailurePredictStatus

 

The most immediate concern is – what is the status of our disks

function test-diskstatus {            
[CmdletBinding()]            
param (            
 [string]$computername = $env:COMPUTERNAME            
)            
            
Get-WmiObject -Namespace root\wmi -Class MSStorageDriver_FailurePredictStatus -ComputerName $computername |            
select InstanceName, Active, PredictFailure, Reason            
            
}

The InstanceName is long so the best display is list

PS> test-diskstatus | fl


InstanceName   : IDE\DiskST9250320AS_____________________________HP07____\5&b0fd174&0&1.0.0_0
Active         : True
PredictFailure : False
Reason         : 0

 

The PredictFailure is the the important property & we worry when it is true!

Posted by RichardSiddaway | with no comments
Filed under:

Finding Domain Controllers

Domain Controllers are the keys to the kingdom as far as AD is concerned. Once we can find them we can do all sorts of stuff. So how do we find them?

if (-not (Get-Module ActiveDirectory)){            
  Import-Module ActiveDirectory            
}            
            
$ou = "OU=Domain Controllers,DC=Manticore,DC=org"            
            
"`nMicrosoft"            
Get-ADDomainController -Filter * | Format-Table Name, ComputerObjectDN            
            
"`nAD provider"            
Get-ChildItem -Path Ad:\$ou | Format-table            
            
"`nQuest"            
Get-QADComputer -ComputerRole "DomainController"            
            
"`nScript"            
$domain = [System.DirectoryServices.ActiveDirectory.Domain]::GetCurrentDomain()            
$domain.FindAllDomainControllers() | select Name

The code using the provider assumes that the domain controllers have been left in the default location – you shouldn’t move them – otherwise the the techniques will retrieve them based on AD information

Folder information on remote machines

A question in the forums wanted to get the date a folder was changed on their domain controllers. This is one way to do it

$folder = "Common Files"            
            
[System.DirectoryServices.ActiveDirectory.Domain]::GetCurrentDomain() |             
select -ExpandProperty DomainControllers |             
foreach {            
 $dc = $_.Name            
            
 if (Test-Path -Path "\\$dc\c$\Program Files (x86)\$folder") {            
  $data =  Get-Item "\\$dc\c$\Program Files (x86)\$folder" | select Fullname, LastWriteTime            
 }            
 else {            
  $data =  Get-Item "\\$dc\c$\Program Files\$folder" | select Fullname, LastWriteTime            
 }            
 $data | Add-Member -MemberType NoteProperty -Name Server -Value $dc -PassThru            
}

In this case the folder would only be in the 32 bit program files folder so see if “program files (x86)” exists – if so its 64 bit machine & we want that folder. if not we revert to “program files”

Final act is to add the computer name as a parameter – that could also be done as a calculated field in select

Posted by RichardSiddaway | with no comments
More Posts Next page »