Posts RSS Comments RSS 244 Posts and 358 Comments till now

Archive for December, 2007

AD Replication Metadata (when did that change?)

There was a discussion on the NG about determining when a user was disabled. The initial request was to determine this based on whenChanged, but I thought that could be invalid as you can easily change an account after it was disabled. I can not think of a way to be sure, but the best way I can think of is to use the replication metadata on the attribute userAccountControl (the second bit is what determines if its disabled or not.) While it is possible to change the useraccountcontrol after a user is disabled it is unlikely.

More info for UserAccountControl bits

http://support.microsoft.com/kb/305144

Of course the next question was how do you check the Replication Metadata for an attribute on and AD object?

Enter Get-ADObjectREplicationMetadata.ps1

This uses

System.DirectoryServices.ActiveDirectory.DirectoryContext
– http://msdn2.microsoft.com/en-us/library/system.directoryservices.activedirectory.directorycontext.aspx
System.DirectoryServices.ActiveDirectory.DomainController
– http://msdn2.microsoft.com/en-gb/library/system.directoryservices.activedirectory.domaincontroller.aspx

# Get-ADObjectREplicationMetadata.ps1
# Brandon Shell (www.bsonposh.com)
# Purpose: Get attribute(s) Replication Metadata from a Domain controller.
Param($Domain,$objectDN,$property)
# Sets Context to Domain for System.DirectoryServices.ActiveDirectory.DomainController
$context = new-object System.DirectoryServices.ActiveDirectory.DirectoryContext("Domain",$domain)
# .NET Class that returns a Domain Controller for Specified Context
$dc = [System.DirectoryServices.ActiveDirectory.DomainController]::findOne($context)
# GetReplicationMetadata returns metadate from the DC for the DN specified.
$meta = $dc.GetReplicationMetadata($objectDN)
if($property){$meta | %{$_.$Property}}else{$meta}

This will return either all the metadata or just the metadata for a specific attribute. I should note that if you do not specify an attribute it returns all of them. You should expect to parse these as each attribute has a child object with the data in it.

All Attributes. The value can be found by .PropertyName

PS# .\Get-ADObjectMetaData.ps1 ‘my.lab.domain’ ‘CN=TestUser,DC=my,dc=lab,dc=domain’

Name                           Value
—-                           —–
countrycode                    System.DirectoryServices.ActiveDirectory.AttributeMetadata
cn                             System.DirectoryServices.ActiveDirectory.AttributeMetadata
mail                           System.DirectoryServices.ActiveDirectory.AttributeMetadata
scriptpath                     System.DirectoryServices.ActiveDirectory.AttributeMetadata
ntsecuritydescriptor           System.DirectoryServices.ActiveDirectory.AttributeMetadata
accountexpires                 System.DirectoryServices.ActiveDirectory.AttributeMetadata
displayname                    System.DirectoryServices.ActiveDirectory.AttributeMetadata
profilepath                    System.DirectoryServices.ActiveDirectory.AttributeMetadata
primarygroupid                 System.DirectoryServices.ActiveDirectory.AttributeMetadata
unicodepwd                     System.DirectoryServices.ActiveDirectory.AttributeMetadata
objectclass                    System.DirectoryServices.ActiveDirectory.AttributeMetadata
objectcategory                 System.DirectoryServices.ActiveDirectory.AttributeMetadata
instancetype                   System.DirectoryServices.ActiveDirectory.AttributeMetadata
homedrive                      System.DirectoryServices.ActiveDirectory.AttributeMetadata
samaccounttype                 System.DirectoryServices.ActiveDirectory.AttributeMetadata
homedirectory                  System.DirectoryServices.ActiveDirectory.AttributeMetadata
whencreated                    System.DirectoryServices.ActiveDirectory.AttributeMetadata
useraccountcontrol             System.DirectoryServices.ActiveDirectory.AttributeMetadata
msmqsigncertificates           System.DirectoryServices.ActiveDirectory.AttributeMetadata
dbcspwd                        System.DirectoryServices.ActiveDirectory.AttributeMetadata
title                          System.DirectoryServices.ActiveDirectory.AttributeMetadata
samaccountname                 System.DirectoryServices.ActiveDirectory.AttributeMetadata
supplementalcredentials        System.DirectoryServices.ActiveDirectory.AttributeMetadata
userparameters                 System.DirectoryServices.ActiveDirectory.AttributeMetadata
givenname                      System.DirectoryServices.ActiveDirectory.AttributeMetadata
description                    System.DirectoryServices.ActiveDirectory.AttributeMetadata
lmpwdhistory                   System.DirectoryServices.ActiveDirectory.AttributeMetadata
pwdlastset                     System.DirectoryServices.ActiveDirectory.AttributeMetadata
msnpallowdialin                System.DirectoryServices.ActiveDirectory.AttributeMetadata
codepage                       System.DirectoryServices.ActiveDirectory.AttributeMetadata
name                           System.DirectoryServices.ActiveDirectory.AttributeMetadata
ntpwdhistory                   System.DirectoryServices.ActiveDirectory.AttributeMetadata
userprincipalname              System.DirectoryServices.ActiveDirectory.AttributeMetadata
admincount                     System.DirectoryServices.ActiveDirectory.AttributeMetadata
objectsid                      System.DirectoryServices.ActiveDirectory.AttributeMetadata
sn                             System.DirectoryServices.ActiveDirectory.AttributeMetadata
msmqdigests                    System.DirectoryServices.ActiveDirectory.AttributeMetadata
logonhours                     System.DirectoryServices.ActiveDirectory.AttributeMetadata
lastlogontimestamp             System.DirectoryServices.ActiveDirectory.AttributeMetadata

Here is a specific Attribute

PS# .\Get-ADObjectMetaData.ps1 ‘my.lab.domain’ ‘CN=TestUser,DC=my,dc=lab,dc=domain’ ‘useraccountcontrol’

Name                        : userAccountControl
Version                     : 8
LastOriginatingChangeTime   : 9/15/2005 1:45:32 PM
LastOriginatingInvocationId : eeaeb6f9-8422-dddd-as34-04d7bd779285
OriginatingChangeUsn        : 47264036
LocalChangeUsn              : 49555172
OriginatingServer           : dc.my.lab.domain

Me, Dean and A couple of Admins Podcasting (what fun!)

I was lucky enough to spend some time with the ACOAP (A couple of Admins Podcasting) guys and a friend (and fellow MVP) Dean Wells. We had a blast just discussing the MVP program and Other MS programs.

The ‘after party’ was really fun, but we only had so much time for the actual podcast so it had to get trimmed. We hope to do another session with them.

Podcast Here
Episode 28 – MVP’s In The House
www.acoupleofadmins.com

More Info for Dean Wells and MSETechnology
www.msetechnology.com

Get-CitrixServerLoad (The power of objects in Citrix)

I watch the forums at BrianMadden.com because I use Powershell a lot for Citrix. This question was brought up.

Q: How could one:
- query “server load” on all servers part of the farm
- extract all server under a minimum server load
- apply an “Offline” load evaluator on the extracted servers (in order to make them unavailable on the farm)

I posted a script to do what they wanted, but then I got to thinking… while it did achieve the goal it wasn’t very Powershellish.

As I have said over and over. The glory of Powershell is the objects. So I decided to Post this entry showing what I would consider the Powershell way :)

Ideally you should just do this at the prompt

PS> Get-CitrixServers | where{$_.WinServerObject.Serverload -lt $load} | Set-CitrixLoadEvalutor “OffLine”

This is easy to achieve with the following scripts or even better make them functions!

Get-CitrixServers

param($Server)
$type = [System.Type]::GetTypeFromProgID("MetaframeCOM.MetaframeFarm",$Server)
$mfarm = [system.Activator]::CreateInstance($type)
$mfarm.Initialize(1)
$mfarm.zones | foreach-Object{$_.OnlineServers}

Set-CitrixLoadEvalutor

Param($server,$LoadEvaluator = "MFDefaultLE",[switch]$Verbose)
#NOTE: This only work for 4.0 and 4.5
if($verbose){$verbosepreference = "Continue"}

function Set-LE{
    Param($mySrv)
    # Getting Current LE
    write-Verbose "   + Set-LE called : $($mySrv.ServerName)"
    $le = $mfServer.AttachedLE
    $le.LoadData(1)
    Write-Verbose "     – Old Evaluator: $($le.LEName)"
    Write-Verbose "     – Setting to $LoadEvaluator"

    # Assigning New LE
    $mySrv.AttachLEByName($LoadEvaluator)

    # Checking LE
    $le = $mySrv.AttachedLE
    $le.LoadData(1)
    Write-Verbose "     – Load Evaluator Set to $($le.LEName)"

}

if($Server)
{
    # Loading Server Object
    Write-Verbose " + Processing $Server"
    $type = [System.Type]::GetTypeFromProgID("MetaframeCOM.MetaframeServer",$Server)
    $mfServer = [system.Activator]::CreateInstance($type)
    $mfServer.Initialize(6,$Server)
    Write-Verbose "   – Calling Set-LE"
    Set-LE $mfServer
}

if($list)
{
    foreach($Srv in (Get-Content $list))
    {
        Write-Verbose " + Processing $Srv"
        # Loading Server Object
        Write-Verbose "   – Getting Citrix Object"
        $type = [System.Type]::GetTypeFromProgID("MetaframeCOM.MetaframeServer",$Srv)
        $mfServer = [system.Activator]::CreateInstance($type)
        $mfServer.Initialize(6,$Srv)
        Write-Verbose "   – Calling Set-LE"
        Set-LE $mfServer
    }
}

if($input)
{
    foreach($Srv in $input)
    {
        Write-Verbose     " + Processing $Srv"
        if($Srv.ServerName)
        {
            Write-Verbose "   – Input is a Citrix Server: $Srv"
            Write-Verbose "   – Calling Set-LE"
            Set-LE $Srv
        }
        else
        {
            Write-Verbose "   – Input: $Srv"
            # Loading Server Object
            Write-Verbose "   – Getting Citrix Object"
            $type = [System.Type]::GetTypeFromProgID("MetaframeCOM.MetaframeServer",$Srv)
            $mfServer = [system.Activator]::CreateInstance($type)
            $mfServer.Initialize(6,$Srv)
            Write-Verbose "   – Calling Set-LE"
            Set-LE $mfServer
        }
    }
}

This was the all in one that I posted

Param($Server,$minLoad = 1000,$LoadEval,[switch]$verbose)
if($verbose){$verbosepreference = "continue"}
function Get-CitrixFarm{
    param($Srv)
    $type = [System.Type]::GetTypeFromProgID("MetaframeCOM.MetaframeFarm",$Srv)
    $mfarm = [system.Activator]::CreateInstance($type)
    $mfarm.Initialize(1)
    Write-Verbose "Loading Farm $($mFarm.FarmName)"
    return $mFarm
}
function Set-CitrixLoadEvalutor{
    Param($server,$LoadEvaluator = "MFDefaultLE")

    # Loading Server Object
    $type = [System.Type]::GetTypeFromProgID("MetaframeCOM.MetaframeServer",$Server)
    $mfServer = [system.Activator]::CreateInstance($type)
    $mfServer.Initialize(6,$Server)

    # Getting Current LE
    $le = $mfServer.AttachedLE
    $le.LoadData(1)
    Write-Verbose "Old Evaluator: $($le.LEName)"
    Write-Verbose "Setting Load Evaluator on $server to $LoadEvaluator"

    # Assigning New LE
    $mfServer.AttachLEByName($LoadEvaluator)

    # Checking LE
    $le = $mfServer.AttachedLE
    $le.LoadData(1)
    Write-Verbose "Load Evaluator Set to $($le.LEName)"
}

$farm = Get-CitrixFarm $Server
foreach($ctxServer in $farm.Servers)
{
    $load = $ctxServer.WinServerObject.Serverload
    Write-Host ("{0,-15} :: {1}" -f $ctxServer.ServerName,$load)
    if($load -lt $minLoad)
    {
        Write-Verbose "Setting Offline Load Eval"
        if($LoadEval){Set-CitrixLoadEvalutor $ctxServer.ServerName $LoadEval}
    }
}