Thursday, February 19, 2009

5 things I've Learned From my Apple Friends


These are a few of the things I've learned from family and friends who use, and swear by, Apple products:

1. Apple products are superior to all other products in the world today, regardless of category. They are superior to all man-made inventions before them and all that will ever be produced.

2. Apple customers are more intelligent, and therefore "superior", to all other humans and life forms, except maybe for Dolphins. Mankind has suffered historical problems only because the world hasn't been run by Apple.

3. Steve Jobs walks on water, speaks to animals, feels "the Force", and can predict winning lottery numbers. He once appeared in the Old Testament, but was removed when Microsoft bought the rights to The Bible. Apparently some versions went so far as to replace "Steve" and "Bill" with "Cain" and "Able" as well. Oh, the blasphemy of it all.

4. Apple computers are immune to viruses (virii?), trojans, worms and all forms of malware. They are also immune to radiation, electromagnetic interference, extreme heat and cold, political unrest, and bonecrushing pressure. In fact, if you put them under sufficient pressure long enough, they turn into diamonds.

5. If everyone bought only Apple products, it would be the end of all bad things known to mankind. No starvation, disease, war, killing, dishonesty (Apple fans are incapable of lying), depression, angst, sadness, malaise and warts.

I'm sure there's more I'm forgetting, but that's only because I don't use an Apple computer.

You've Been Laid Off. Now What?


Several acquaintances I've "spoken with" recently (by email) have either been laid off, or are facing the real possibility of being laid off.  Having gone through it early in this "Recession" (Q2-08) for the first time in my life, I thought I could offer something to help.  Maybe.  Some of my friends find it odd that at age 44 I hadn't been laid off before.  I've been "furlowed" before, back in the 1980's, but that's about it.

Let's face it, there's really nothing *I* can offer that will really  "help" ease the stress or pain of that.  But I can at least provide a few insights on what you can expect, and some ways you can cope with it to lessen the stress and emotional beating you might otherwise endure.  Rather than blabber in paragraph form, I thought it would be best to say it in bullet-list format for simplicity and clarity:

- First off: File for unemployment right away.  Do that before you stop at the bar or the gun shop.

- You're going to feel depressed. Probably not for a few days later, when the reality sets in.  Maybe only a little.  Maybe a lot.  Don't give up.  Being laid off is tough for anyone to deal with.  It will be toughest at night, but reading helps get your mind off of it.

- Stay close with family and friends.  Seek out friends wherever you can, but don't lean on them too heavy with "needing a job".  Ask them for help reviewing your resume, but that's about it.

- Don't confuse "friends" with "colleagues".  This is not to say that there aren't friendly colleagues or that colleagues are somehow bad.  But don't lean on them like you would with "friends".

- Get a new hobby or brush up on an old hobby.  Physical activity is best.  Walking, jogging, hiking, biking, guitar, painting, whatever.  Get outdoors in the sun as often as you can.  Even if only for a few minutes.

- Avoid drinking.  Quit smoking also.  Eat healthy foods.  This would be a great time to adopt some healthy living habits.

- Avoid things that keep you up at night.  Turn off the TV.  Read.  Lack of sleep only makes things worse and screws with your emotional stability.  Don't listen to depressing music.  "Nutshell" by Alice in Chains is probably not good for you to go to bed with right now.

- Be nice to everyone as much as you can.  Don't assume they can understand what you're feeling and don't blame them for that either.

- Get up early every day, shower and get dressed.  Don't lay around sloppy.  Eat a good breakfast.  The effect of this on your sanity is incredible.

- Have lunch with friends and people you network with.  This keeps your mind tuned by staying involved with people in social settings.

- Sharpen your skills for whatever job you intend to pursue.  You have the time so make the best use of it.  If you can afford to enroll in classes at a nearby school, do it.

- Keep fine-tuning your resume and apply for jobs wherever you find them.  Don't use the same exact resume for every application.  Fine tune each one to suit the job posting.

- Don't be discouraged if an interview doesn't go well.  I applied for roughly twenty jobs the first two weeks after I was laid off, which resulted in two interviews.  Neither worked out, but I took the opportunity to review what I did and didn't do well and continued to work on it.

- Be aware of the job market relative to your skills, your location, the local economy, and how these all mix together into relative opportunities.  If your skills are more marketable elsewhere, and you can relocate, do it.  Use Dice.com, Monster.com and others to help open up possibilities.  For every local position I found, I was contacted for five in other cities, but I couldn't relocate for a variety of reasons.

- Be realistic, but strive to be optimistic.  Find humor in everything.  It's there.

I hope this helps.  It helped me a lot.

Tuesday, February 17, 2009

RSAT on Windows Vista, Windows 7

I'm seeing a strange pattern with respect to RSAT lately. I have no idea why, but today I had the third person in two weeks e-mail me about how to get it to work on their Vista or Win7 computers. In all three cases, they installed the RSAT MSU patch file and then went looking for the RSAT tools immediately, but none were to be found.

It seems they didn't read the associated KB article (941314) linked from the download page. (That's ok: I missed it too the first time, and went stumbling around for it like they did). The KB article describes what RSAT is, what tools are included, and most importantly: how to install, and uninstall it. The key section would be "Install RSAT" about 2/3 down the KB article page. Oddly enough, the Windows 7 RSAT download page includes all of this information on one page. Microsoft usually gets things right eventually.

RSAT, or "Remote Server Administration Tools", is the new name for the former "Administration Tools Pack", or "Admin Pack", for Windows Server 2003. The Microsoft RSAT team threw in GPMC, and a few other extraneous tools as well, which is very much appreciated (by me anyway).



To make it a little easier: After you install RSAT, go into Control Panel, open Programs, and select Turn Windows Features On or Off. Locate the entry for "Remote Server Administration Tools" and enable it there. You can enable individual tools within RSAT or the entire suite if you prefer. Don't forget to enable "Administration Tools" on the Start Menu also.

To verify installation on Windows Vista, go to Control Panel, Programs, and click on "View Installed Updates". Look for the entry "Update for Microsoft Windows (941314)". On Windows 7, look for entry "Update for Microsoft Windows (958830)". Alternatively, you can search for the file "rsatclient.dll" in the %WINDIR%\System32 folder.

Downloads:


More Information:

KB934307 - Description of the Windows Update Stand-alone Installer (Wusa.exe) and of .msu files in Windows Vista and in Windows Server 2008

Trent 4.0 "released" (chuckle)

Rod Trent and his wife finally welcomed Ellyanna Lynn Trent on Feb 16, 2009.  Congrats!  Here's a pic.

Windows 7 / 2008 R2 Managed Service Accounts

For years I have argued that making domain "service" accounts is stupid.  Most people look at me like I'm clacking sounds with duck lips and dancing on one foot.  Seriously, it's dumb.  I've seen so many environments where admins create "service" accounts in AD just "because".  It's a habit that started with NT4 and never died.

There are still a few (rare) cases when it makes sense, but since Windows XP and Windows Server 2003, it almost always make better sense to use computer accounts and grant rights accordingly.  That means using the local "System" account.  Ever seen the "Domain Computers" group and wondered what it was good for? How about those Computer$ accounts?  Because this makes people have to think (and many hate to think) they don't want to bother with GPO issues, and so forth.  But it really is easier and simpler to manage once you go that route.

This isn't my idea.  Microsoft has been pushing for this for a long time.  Anyone who has implemented SMS 2003 or SCCM knows what I'm talking about.  It was called "Advanced Security" but it's really simple security, because you don't have to worry about passwords or access to the account itself, because it's the computer account and only people with local Admin rights to the computer could commandeer the account for malicious or unauthorized use.  Compare that with a domain user account which is essentially floating in the open and doesn't need to be instantiated from a specific host on the domain. 

Windows 7 and Windows Server 2008 R2 now introduce a new type of domain account called a Managed Service Account.  This is an interesting concept and should bring a smile to the faces of those who want to get away from the old way but are daunted by the challenges of dealing with some of the obscure issues of the "new way" using computer accounts.  But what was disappointing for me was learning that the only way to create an MSA is by using PowerShell.  I had been searching and reading and wondered about the new option in ADUC (which they show and discuss on the AD Doc Team blog), but the PowerShell approach is the only way that works right now.  I can't tell if that is going to be the permanent solution, or if it's just during the beta.

Part of it makes sense.  Somewhat like how you have to manually enable the AD Schema Management MMC snap-in, or turn on "Advanced Features" in ADUC in order to access the Security tab on objects.  The implication is that it is a sensitive, critical feature, and should therefore be somewhat obtuse and obscure to access.  This helps avoid accidental screw-ups for sure.  But I wonder if an MSA is "that" touchy.

I made the claim that I was moving away from Active Directory, SMS, System Center, and so on, which I definitely have.  Not by choice, but by circumstance.  This was just something that got me thinking again after a long time away from it.  That said, I think I won't be posting techy stuff here anymore except for script code if anything.

Monday, February 16, 2009

Windows 7 GPEDIT Changes

I really like, no LOVE, Windows 7.  I wish I was paid to say that, but I can assure you I wouldn't be driving what I drive if I were.  Like Vista, it is packed with tons of little feature improvements all over the place.  Some are really noticable, like the new Taskbar, Start Menu, and so on.  Some are more subtle, but to some people, like me, when they stumble on them we get a big surprise.  For others, they couldn't care less.

One example is the age-old Local Policy editor: GPEDIT.msc.  At first glance, it looks identical to Vista's implementation.  However, when you double-click on a setting and it opens the properties dialog, you will see a huge difference.  The dialog form is completely redesigned.  At first I thought it was nice.  That soon faded to "interesting", but then my years of software engineering and UI thinking patterns bubbled up and I started wondering if it was even given real design consideration, or just thrown in ad hoc.  Technically speaking, not subjectively, objectively, it is flawed.  Minor?  Trivial?  Arguably: yes.  But flawed it is.

Take a look...

There are quite a few major improvements over the dialog form provided in Windows XP and Windows Vista.  Combining multiple tabs on one "panel" is helpful, but there's a few UI goofs.  See anything wrong?

If you stare at it long enough you should pick out at least three rules of UI design broken.  These are UI 101 rules by the way, nothing "advanced".  Here's a "Dave Version" below to compare with.  This is not implying that MY version is "correct".  There is no *one* "correct" way to design a user interface.  This is simply ONE way.  But it's enough to contrast with the actual implementation to highlight what could be improved.


Need a few hints?  Note the relocated "Previous" and "Next" buttons.  Note the expanded region for the caption text (e.g. "Always open All Control Panel...") along the top.  Note the expanded region for the text box under "Comment:".  Most importantly, these changes were easily made within 30 seconds and without modifying the other form objects nor the overall size or aspect ratio of the form panel itself.

On one hand, I have to allow Microsoft some wiggle room because this is a "Beta" release and things like this are par for the course.  However, as many have also said (complained?): Microsoft isn't treating this "beta" like past "beta" programs.  The bi-directional communication channels are actually unilateral this time around.  This beta is being handled more like a typical Release Candidate (RC), so going on that assumption, which seems to be widely accepted, I doubt this "feature" will see any significant improvement between now and the RC or RTM milestones.  But who really knows?  This is just one thing I find interesting and a bit surprising as well.

When a Lie is Repeated Enough...

It becomes "truth".  Right?  We've heard that saying before.  It seems it's true.  Here's a few that bug me quite often:

America Thrives on a "Free Market" economy, right?

Wrong!  If we did have a "free market" economy, there would be NO government intervention or oversight of anything.  Businesses would regulate themselves without any government intrusion or regulation.  That's the definition of "free market" after all.  There wouldn't be any such thing as "anti-trust" or the Sherman Act, nor would there be agencies like the FCC, FDA or the SEC.

America is a "Democracy".  Right?

Wrong again!  Technically, our current governmental system is a hybrid of multiple classic systems.  Part "republic", part "capitalist", part "oligarchy" (whether you believe it or not), and part "corporation".  After all, what is the Federal Reserve?  Think you know?  Go check it out.

The Federal Reserve is a Government Agency.  Right?

Nope.  It's a group of private bankers who form a board with "limited" oversight by a government representative.  The names of the members of the board are not shared with the public.  They are kept secret.  They control a significant portion of our financial system, and hence our national existence and stability, yet they are not a government entity.  Think about that for a moment.

Presidents are elected by Popular Vote.  Right?

Completely false.  The popular vote, which are the votes cast by "ordinary citizens", whatever that means, are simply used as a guidance for the Electoral College.  The Electoral College is a body of representatives who cast their vote to determine the winner of the presidential election.  There have been two cases in American history when the Electoral College cast their vote in opposition to the popular vote.  This occurred in 1876, 1888, 1824 and 2000.  Still think we have a "democracy"?

A "Monopoly" is Illegal in the U.S.

Wrong.  Some monopolies are allowed.  The Anti Trust act and subsequent addendums simply provide the means and the legal ability for the government to intervene and take action to prevent or remove a monopoly if deemed necessary for the national interest.

A "Commonwealth" is not a "State". Right?

At one time that was true, and it held legal significance.  Differences in legal rights or policies that exist today are not directly associated with the title "commonwealth" but rather with the government of each body (state, commonwealth).

An American Citizen Can "Own" Land.  Right?

Sort of.  In most cases a citizen owns "rights" to use land or live upon it, under some restrictions or conditions (local codes and restrictions for example).  Rarely does an individual own unlimited rights to their land.  For example, "mineral" or "drilling" rights, should oil, or precious minerals.  Regardless, local, state and federal government may occupy or sieze land owned by a citizen under the right of "eminent domain" for reasons which affect national security, or special public interests (highway construction, facilities construction, toxic material removal, and so on).

American Currency is Based on Gold.  Right?

Wow, where have you been?  The Bretton-Woods Agreement, signed in 1944, effectively ended the use of Gold as a basis of value for currency in America.  The "value" of our money is simply an agreed-upon reference that is monitored and regulated, with limited effect, by our government, and the Federal Reserve.

"One Nation, Under God"...

The words "Under God" were officially added to the Pledge of Allegiance by President Dwight D. Eisenhower in 1954.  The words were not officially part of the Pledge prior to that, even though they were publicly accepted and used as early as 1951.

The Truth?

Do they teach these "caveats" to kids in our public schools?  I've never seen or heard of it anywhere.  None of my four kids have ever been taught any of this, even though it is all public information that is easily accessible from official sources such as local, state and federal government web sites, public libraries, country municipal agencies, and so on.

Script Code: Active Directory Data Extraction

Here's a portion of a script that I used to extract information from client Active Directory environments to assess their "health" and for supporting project plans, etc. I don't use it anymore, so maybe it can benefit someone else.  If this doesn't suit your needs, feel free to modify it.  You can find tons of other scripts to do this as well if you search the web.  Check out Don Hite's web site, as well as Cruto for other examples.

'****************************************************************
' Filename..: ad_env_query.vbs
' Author....: David Stein
' Date......: 11/21/07
' Purpose...: query active directory forest envirnment information
' SQL.......: N/A
' Comments..: usage:
'
'   cscript /nologo ad_env_query.vbs
'
'   to capture output to file, append output redirect...
'
'   cscript /nologo ad_env_query.vbs >ad_query.txt
'****************************************************************

'----------------------------------------------------------------
' comment: toggle options on/off via the following variables
'----------------------------------------------------------------

' these control showing total counts for objects

Const CountUsers       = False ' count user accounts
Const CountGroups      = False ' count security groups
Const CountComputers   = False ' count computers
Const CountPrinters    = False ' count published shared printers
Const CountServers     = False ' count servers
Const CountSpecUsers   = False ' count users with non-exp passwords
Const CountContacts    = False ' count contacts
Const CountDisabled    = False ' count disabled user accounts

' these control enumerating object names

Const ShowAllDomains   = False ' show all domains in forest
Const ShowAllUsers     = False ' show user accounts
Const ShowSpecUsers    = False ' show users with non-exp passwords
Const ShowAllContacts  = False ' show contacts
Const ShowAllGroups    = False ' show security groups
Const ShowAllComputers = False ' show computers
Const ShowAllPrinters  = False ' show published shared printers
Const ShowAllTrusts    = False ' show domain trusts
Const ShowAllShares    = False ' show published shares
Const ShowAllDisabled  = False ' show disabled user accounts

' these control enumerating domain structural items

Const ShowFSMO       = False ' show fsmo role holders
Const ShowAllSites   = False ' show all ad sites
Const ShowRootInfo   = False ' show RootDSE properties
Const ShowOUs        = False ' show OU tree structure
Const ShowContainers = True ' include containers when showing OU structure
Const ShowAllGPOs    = False ' show all group policy objects
Const ShowNetlogon   = False ' show contents of netlogon share

' note: [ShowContainers] is only used when [ShowOUs] is TRUE

'----------------------------------------------------------------
' ***  IMPORTANT: DO NOT MODIFY CODE BELOW THIS POINT !!!  ***
'----------------------------------------------------------------
Dim LDAP_DN, objRootDSE, objWMIService, wshNetwork, wshShell
Dim ADSI_DN, objFSO

Const NTDSDSA_OPT_IS_GC = 1
Const ADS_SCOPE_SUBTREE = 2
Const ADS_UF_ACCOUNTDISABLE = 2
Const strComputer = "."

On Error Resume Next
Set objRootDSE = GetObject("LDAP://rootDSE")
Set wshNetwork = CreateObject("WScript.Network")
Set wshShell   = CreateObject("WScript.Shell")
Set objWMIService = GetObject("winmgmts:\\" & strComputer & "\root\CIMV2")
Set objFSO = CreateObject("Scripting.FileSystemObject")
If err.Number <> 0 Then
    wscript.echo "ERROR: Failed to instantiate objects required for query"
    wscript.echo "Details: " & err.Number & " / " & err.Description
    wscript.Quit
End If

'----------------------------------------------------------------
' comment: query for LDAP domain DN (eg. DC=domain,DC=com)
'----------------------------------------------------------------

LDAP_DN = Domain_LDAP()
ADSI_DN = Domain_NetBIOS(LDAP_DN)

'----------------------------------------------------------------
' comment: begin processing
'----------------------------------------------------------------

ShowBasicInfo()
ShowPwdPolicy()
ShowDomainControllers()

If ShowRootInfo = True Then ShowRootDSEinfo()
If ShowAllDomains = True Then ShowDomains()
If ShowAllTrusts = True Then ShowTrusts()
If ShowFSMO = True Then ShowRoles()
If ShowAllSites = True Then ShowSites()
If ShowOUs = True Then EnumOUs()

If CountComputers = True Then EnumComputers "COUNT"
If CountServers = True Then EnumServers "COUNT"
If CountGroups = True Then EnumGroups "COUNT"
If CountUsers = True Then EnumUsers "COUNT"
If CountSpecUsers = True Then ShowSpecialUsers "COUNT"
If CountDisabled = True Then EnumDisabledUsers "COUNT"
If CountContacts = True Then EnumContacts "COUNT"
If CountPrinters = True Then EnumPrinters "COUNT"

If ShowAllServers = True Then EnumServers ""
If ShowAllComputers = True Then EnumComputers ""
If ShowAllGroups = True Then EnumGroups ""
If ShowAllUsers = True Then EnumUsers ""
If ShowSpecUsers = True Then ShowSpecialUsers ""
If ShowAllDisabled = True Then EnumDisabledUsers ""
If ShowAllContacts = True Then EnumContacts ""
If ShowAllPrinters = True Then EnumPrinters ""
If ShowAllGPOs = True Then EnumGPOs()
If ShowNetlogon = True Then NetlogonShare()
If ShowAllShares = True Then EnumShares ""

'ShowOU_GPO_Info "LDAP://ou=Domain Controllers," & LDAP_DN

Set wshNetwork = Nothing
Set wshShell   = Nothing

'----------------------------------------------------------------

Function Domain_LDAP()
    Dim retval
    retval = objRootDSE.Get("defaultNamingContext")
    Domain_LDAP = retval
End Function

'----------------------------------------------------------------

Function Domain_NetBIOS(ldapdn)
    Domain_NetBIOS = Replace(Replace(ldapdn,"DC=",""),",",".")
End Function

'----------------------------------------------------------------

Sub ShowBasicInfo()
    wscript.echo vbCRLF & "# GENERAL INFORMATION" & vbCRLF
    Dim strPCName, strUserName, strDomain
    strPCName   = wshNetwork.ComputerName
    strUserName = wshNetwork.UserName
    strDomain   = wshNetwork.UserDomain
    wscript.echo "user_domain....: " & strDomain
    wscript.echo "domain_ldap....: " & LDAP_DN
    wscript.echo "computername...: " & strPCName
    wscript.echo "username.......: " & strUserName
    wscript.echo "report_date....: " & Now
End Sub

'----------------------------------------------------------------

Sub ShowPwdPolicy()
    Dim objDomain, maxPwdAge, minPwdAge, minPwdLen
    Dim acctLockoutDur, acctLockoutThreshold, acctLockoutWait
    Dim pwdHistory
    Set objDomain = GetObject("LDAP://" & objRootDSE.Get("defaultNamingContext"))

    'convert to days...
    maxPwdAge = Int(Int8ToSec(objDomain.Get("maxPwdAge")) / 86400)

    'convert to days...
    minPwdAge = Int8ToSec(objDomain.Get("minPwdAge")) / 86400

    minPwdLen = objDomain.Get("minPwdLength")

    'convert to minutes...
    acctLockoutDur = Int8ToSec(objDomain.Get("lockoutDuration")) / 60
    acctLockoutThreshold = objDomain.Get("lockoutThreshold")

    'convert to minutes...
    acctLockoutWait = Int8ToSec(objDomain.Get("lockoutObservationWindow")) / 60 
    pwdHistory = objDomain.Get("pwdHistoryLength")
    wscript.echo vbCRLF & "# DOMAIN PASSWORD POLICY SETTINGS" & vbCRLF
    wscript.echo "max_pwd_age....: " & maxPwdAge & " days"
    wscript.echo "min_pwd_age....: " & minPwdAge & " days"
    wscript.echo "pwd_history....: " & pwdHistory & " passwords remembered"
    wscript.echo "min_pwd_length.: " & minPwdLen & " chars"
    wscript.echo "lockout_dur....: " & acctLockoutDur & " minutes"
    wscript.echo "lockout_thresh.: " & acctLockoutThreshold & " invalid logon attempts"
    wscript.echo "reset_wait.....: " & acctLockoutWait & " minutes"
End Sub

'----------------------------------------------------------------
' function: convert Integer8 64-bit numbers to seconds (time)
'----------------------------------------------------------------

Function Int8ToSec(ByVal objInt8)
    Dim lngHigh, lngLow
    lngHigh = objInt8.HighPart
    ' adjust for error in IADsLargeInteger property methods
    lngLow = objInt8.LowPart
    If lngLow < 0 Then
        lngHigh = lngHigh + 1
    End If
    Int8ToSec = -(lngHigh * (2 ^ 32) + lngLow) / (10000000)
End Function

'----------------------------------------------------------------

Sub ShowDomains()
    Dim objWMIAD, colItems, objItem
    wscript.echo vbCRLF & "# ACTIVE DIRECTORY DOMAINS" & vbCRLF
    On Error Resume Next
    Set objWMIAD = GetObject("winmgmts:{impersonationLevel=impersonate}!\\" & _
        strComputer & "\root\MicrosoftActiveDirectory")
    Set colItems = objWMIAD.ExecQuery("Select * from Win32_NTDomain")
    For Each objItem in colItems
        If Trim(objItem.DomainName) <> "" Then
            wscript.echo "domain_name....: " & objItem.DomainName
            wscript.echo "client_sitename: " & objItem.ClientSiteName
            wscript.echo "dc_sitename....: " & objItem.DcSiteName
            wscript.echo "description....: " & objItem.Description
            wscript.echo "dns_forestname.: " & objItem.DnsForestName
            wscript.echo "dc_address.....: " & objItem.DomainControllerAddress
            wscript.echo "dc_address_type: " & objItem.DomainControllerAddressType
            wscript.echo "dc_name........: " & objItem.DomainControllerName
            wscript.echo "domain_guid....: " & objItem.DomainGuid
            wscript.echo "ds_flag........: " & objItem.DSDirectoryServiceFlag
            wscript.echo "ds_dns_contflag: " & objItem.DSDnsControllerFlag
            wscript.echo "ds_dns_domflag.: " & objItem.DSDnsDomainFlag
            wscript.echo "ds_dns_forflag.: " & objItem.DSDnsForestFlag
            wscript.echo "ds_gc_flag.....: " & objItem.DSGlobalCatalogFlag
            wscript.echo "ds_kdc_flag....: " & objItem.DSKerberosDistributionCenterFlag
            wscript.echo "ds_pdc_flag....: " & objItem.DSPrimaryDomainControllerFlag
            wscript.echo "ds_timesvc_flag: " & objItem.DSTimeServiceFlag
            wscript.echo "ds_write_flag..: " & objItem.DSWritableFlag
    '        wscript.echo "name...........: " & objItem.Name
    '        wscript.echo "primary_owner..: " & objItem.PrimaryOwnerContact
            wscript.echo
        End If
    Next
End Sub

'----------------------------------------------------------------

Sub ShowDomainControllers()
    Dim objConnection, objCommand, objRecordSet, objDC, icount
    wscript.echo vbCRLF & "# DOMAIN CONTROLLERS" & vbCRLF
    Set objConnection = CreateObject("ADODB.Connection")
    Set objCommand = CreateObject("ADODB.Command")
    objConnection.Provider = "ADsDSOObject;"
    objConnection.open
    objCommand.ActiveConnection = objConnection
    icount = 0
    ldapQuery = "<LDAP://" & objRootDSE.Get("ConfigurationNamingContext") & _
        ">;((objectClass=nTDSDSA));ADsPath;subtree"
    objCommand.CommandText = ldapQuery
    objCommand.Properties("Page Size") = 1000
    Set objRecordSet = objCommand.Execute
    If Not(objRecordSet.EOF And objRecordSet.BOF) Then
        Do While Not(objRecordSet.EOF)
            Set objDC = GetObject(GetObject(objRecordSet.Fields(0).Value).Parent)
            wscript.echo "dc_server_name.: " & objDC.dNSHostName
            objRecordSet.MoveNext
            icount = icount + 1
        Loop
        wscript.echo "dc_servers.....: " & icount
    End If
    objConnection.Close
End Sub

'----------------------------------------------------------------

Sub ShowRoles()
    Dim objSchema, objNtds, objPartitions, objDomain, objRidManager
    Dim objInfrastructure, strSchemaMaster, objComputer, strDomainNamingMaster
    Dim strPdcEmulator, strRidMaster, strInfrastructureMaster
    wscript.echo vbCRLF & "# ACTIVE DIRECTORY SERVER ROLES" & vbCRLF
    Set objSchema = GetObject("LDAP://" & objRootDSE.Get("schemaNamingContext"))
    strSchemaMaster = objSchema.Get("fSMORoleOwner")
    Set objNtds = GetObject("LDAP://" & strSchemaMaster)
    Set objComputer = GetObject(objNtds.Parent)
    wscript.echo "fsmo_schema....: " & objComputer.Name
    Set objNtds = Nothing
    Set objComputer = Nothing
 

    Set objPartitions = GetObject("LDAP://CN=Partitions," & _

        objRootDSE.Get("configurationNamingContext"))


    strDomainNamingMaster = objPartitions.Get("fSMORoleOwner")
    Set objNtds = GetObject("LDAP://" & strDomainNamingMaster)
    Set objComputer = GetObject(objNtds.Parent)
    wscript.echo "fsmo_domain....: " & objComputer.Name

    Set objDomain = GetObject("LDAP://" & objRootDSE.Get("defaultNamingContext"))
    strPdcEmulator = objDomain.Get("fSMORoleOwner")
    Set objNtds = GetObject("LDAP://" & strPdcEmulator)
    Set objComputer = GetObject(objNtds.Parent)
    wscript.echo "fsmo_pdc.......: " & objComputer.Name

    Set objRidManager = GetObject("LDAP://CN=RID Manager$,CN=System," & _

        objRootDSE.Get("defaultNamingContext"))


    strRidMaster = objRidManager.Get("fSMORoleOwner")
    Set objNtds = GetObject("LDAP://" & strRidMaster)
    Set objComputer = GetObject(objNtds.Parent)
    wscript.echo "fsmo_rid.......: " & objComputer.Name

    Set objInfrastructure = GetObject("LDAP://CN=Infrastructure," & _

        objRootDSE.Get("defaultNamingContext"))


    strInfrastructureMaster = objInfrastructure.Get("fSMORoleOwner")
    Set objNtds = GetObject("LDAP://" & strInfrastructureMaster)
    Set objComputer = GetObject(objNtds.Parent)
    wscript.echo "fsmo_im........: " & objComputer.Name
End Sub

'----------------------------------------------------------------

Sub ShowSites()
    Dim strConfigurationNC, strSitesContainer, objSite, sitename
    wscript.echo vbCRLF & "# ACTIVE DIRECTORY SITES" & vbCRLF
    strConfigurationNC = objRootDSE.Get("configurationNamingContext")
    strSitesContainer = "LDAP://cn=Sites," & strConfigurationNC
    Set objSitesContainer = GetObject(strSitesContainer)
    objSitesContainer.Filter = Array("site")
    For Each objSite In objSitesContainer
        sitename = Replace(objSite.Name,"CN=","")
        wscript.echo "site_name......: " & sitename
        ShowSiteDCs objSite.Name
        ShowSiteSubnets objSite.Name
    Next
End Sub

'----------------------------------------------------------------

Sub ShowSiteDCs(strSiteRDN)
    Dim strConfigurationNC, strServersPath, objServer, sitename
    strConfigurationNC = objRootDSE.Get("configurationNamingContext")
    strServersPath = "LDAP://cn=Servers," & strSiteRDN & ",cn=Sites," & strConfigurationNC
    Set objServersContainer = GetObject(strServersPath)
    For Each objServer In objServersContainer
        servername = Replace(objServer.Name,"CN=","")
        sitename = Replace(strSiteRDN,"CN=","")
        wscript.echo vbTab & "dc_server....: " & servername
        ShowConnections servername, sitename
        ShowBridgeHeadTransports servername, sitename
    Next
End Sub

'----------------------------------------------------------------

Sub ShowSiteSubnets(strSiteRDN)
    Dim strConfigurationNC, strSitePath, arrSiteObjectBL 
    Dim strSiteObjectBL
    strConfigurationNC = objRootDSE.Get("configurationNamingContext")
    strSitePath = "LDAP://" & strSiteRDN & ",cn=Sites," & strConfigurationNC
    Set objSite = GetObject(strSitePath)
    objSite.GetInfoEx Array("siteObjectBL"), 0
    arrSiteObjectBL = objSite.GetEx("siteObjectBL")
    For Each strSiteObjectBL In arrSiteObjectBL
        wscript.echo vbTab & "subnet.......: " & _

            Split(Split(strSiteObjectBL, ",")(0), "=")(1)
    Next
End Sub

'----------------------------------------------------------------

Sub EnumOUs()
    wscript.echo vbCRLF & "# ORGANIZATIONAL UNIT STRUCTURE" & vbCRLF
    DisplayObjects "LDAP://" & LDAP_DN, ""
End Sub

Function DisplayObjects( strADsPath, strTab)
    Set objObject = GetObject(strADsPath)
    Set objX = GetObject(strADsPath)
'    wscript.echo strTab & Replace(objX.Name, "OU=", "")
    wscript.echo strTab & objX.Name
    If showContainers = True Then
        objObject.Filter = Array("container","organizationalUnit")
    Else
        objObject.Filter = Array("organizationalUnit")
    End If
    For each objChildObject in objObject
        DisplayObjects objChildObject.ADsPath, strTab & " .. "
    Next
End Function

'----------------------------------------------------------------

Function IsGC(strCN)
    Dim strDsServiceDN, intOptions, objServer
    Set objServer = GetObject("LDAP://" & strCN & "/rootDSE")
    strDsServiceDN = objServer.Get("dsServiceName")
    Set objDsRoot  = GetObject("LDAP://" & strCN & "/" & strDsServiceDN)
    intOptions = objDsRoot.Get("options")
    If intOptions And NTDSDSA_OPT_IS_GC Then
        IsGC = True
    End If
End Function

'----------------------------------------------------------------

Sub ShowTrusts()
    Dim colTrustList, objTrust
    wscript.echo vbCRLF & "ACTIVE DIRECTORY TRUSTS" & vbCRLF
    On Error Resume Next
    If err.Number <> 0 Then
        wscript.echo "unavailable....: non-domain-controller"
        Exit Sub
    End If
    Set colTrustList = objWMIService.ExecQuery("Select * from Microsoft_DomainTrustStatus")
    For each objTrust in colTrustList
        wscript.echo "trusted_domain.: " & objTrust.TrustedDomain
        wscript.echo "trust_direction: " & objTrust.TrustDirection
        wscript.echo "trust_type.....: " & objTrust.TrustType
        wscript.echo "trust_attribs..: " & objTrust.TrustAttributes
        wscript.echo "trusted_dcname.: " & objTrust.TrustedDCName
        wscript.echo "trust_status...: " & objTrust.TrustStatus
        wscript.echo "trust_is_ok....: " & objTrust.TrustIsOK
    Next
End Sub

'----------------------------------------------------------------

Sub EnumServers(mode)
    wscript.echo vbCRLF & "# enumerating server objects..." & vbCRLF
    Dim objRecordSet, varConfigNC, strConnString, strWQL
    Dim objServer, strServerName, strOperatingSystem, retval
    retval = 0
    Set objRecordSet = CreateObject("ADODB.RecordSet")
    varConfigNC = objRootDSE.Get("defaultNamingContext")
    strConnstring = "Provider=ADsDSOObject"
    strWQL = "SELECT * FROM 'LDAP://" & varConfigNC & _
        "' WHERE objectCategory= 'Computer' and OperatingSystem = 'Windows*Server*'"
    objRecordSet.Open strWQL, strConnstring
    If mode = "COUNT" Then
        Do Until objRecordSet.EOF
            retval = retval + 1
            objRecordSet.MoveNext
        Loop
        wscript.echo "Servers......: " & retval
    Else
        Do until objRecordSet.EOF
            Set objServer = GetObject(objRecordSet.Fields.Item(0))
            strServerName = objServer.CN
            strOperatingSystem = objServer.OperatingSystem
            wscript.echo strServerName & vbTab & strOperatingSystem
            objRecordSet.MoveNext
            Set objServer = Nothing
        Loop
    End If
    objRecordSet.Close
    Set objRecordSet = Nothing
End Sub

'----------------------------------------------------------------

Sub EnumComputers(mode)
    wscript.echo vbCRLF & "# enumerating computer objects..." & vbCRLF
    Dim retval, objConnection, objCommand, objRecordSet
    Dim c2000, cXP, cVista, cWin7, cNT, cOther, os
    retval = 0
    c2000 = 0
    cXP = 0
    cVista = 0
    cWin7 = 0
    cNT = 0
    cOther = 0
    Set objConnection = CreateObject("ADODB.Connection")
    Set objCommand =   CreateObject("ADODB.Command")
    objConnection.Provider = "ADsDSOObject"
    objConnection.Open "Active Directory Provider"
    Set objCOmmand.ActiveConnection = objConnection
    objCommand.CommandText = "Select Name, operatingSystem from 'LDAP://" & _
        LDAP_DN & "' where objectClass='computer' and OperatingSystem <> 'Windows*Server*'"
    objCommand.Properties("Page Size") = 1000
    objCommand.Properties("Timeout") = 30
    objCommand.Properties("Searchscope") = ADS_SCOPE_SUBTREE
    objCommand.Properties("Cache Results") = False
    Set objRecordSet = objCommand.Execute
    objRecordSet.MoveFirst
    If mode = "COUNT" Then
        Do Until objRecordSet.EOF
            retval = retval + 1
            objRecordSet.MoveNext
        Loop
        wscript.echo "Computers....: " & retval
    Else
        Do Until objRecordSet.EOF
            os = Trim(objRecordSet.Fields("operatingSystem").Value)
            wscript.echo "Computer.....: " & objRecordSet.Fields("Name").Value & _
                vbTab & os
            Select Case os
                Case "Windows 2000 Professional":
                    c2000 = c2000 + 1
                Case "Windows XP Professional":
                    cXP = cXP + 1
                Case "Windows NT":
                    cNT = cNT + 1
                Case Else:
                    If Left(os, 13) = "Windows Vista" Then
                        cVista = cVista + 1
                    ElseIf Left(os, 9) = "Windows 7" Then
                        cWin7 = cWin7 + 1
                    Else
                        cOther = cOther + 1
                    End If
            End Select
            objRecordSet.MoveNext
        Loop
        wscript.echo "# operating system types..."
        wscript.echo "WinNT........: " & cNT
        wscript.echo "Win2000......: " & c2000
        wscript.echo "WinXP........: " & cXP
        wscript.echo "WinVista.....: " & cVista
        wscript.echo "Win7.........: " & cWin7
        wscript.echo "Other........: " & cOther
    End If
End Sub

'----------------------------------------------------------------

Sub EnumUsers(mode)
    wscript.echo vbCRLF & "# enumerating user account objects..." & vbCRLF
    Dim retval, objConnection, objCommand, objRecordSet
    retval = 0
    Set objConnection = CreateObject("ADODB.Connection")
    Set objCommand =   CreateObject("ADODB.Command")
    objConnection.Provider = "ADsDSOObject"
    objConnection.Open "Active Directory Provider"
    Set objCOmmand.ActiveConnection = objConnection
    objCommand.CommandText = "Select Name, displayName from 'LDAP://" & _
        LDAP_DN & "' where objectCategory='person' and objectClass='user'"
    objCommand.Properties("Page Size") = 1000
    objCommand.Properties("Timeout") = 30
    objCommand.Properties("Searchscope") = ADS_SCOPE_SUBTREE
    objCommand.Properties("Cache Results") = False
    Set objRecordSet = objCommand.Execute
    objRecordSet.MoveFirst
    If mode = "COUNT" Then
        Do Until objRecordSet.EOF
            retval = retval + 1
            objRecordSet.MoveNext
        Loop
        wscript.echo "UserAccounts.: " & retval
    Else
        Do Until objRecordSet.EOF
            wscript.echo "UserAccount..: " & objRecordSet.Fields("Name").Value & _
                vbTab & objRecordSet.Fields("displayName").Value
            objRecordSet.MoveNext
        Loop
    End If
End Sub

'----------------------------------------------------------------

Sub EnumContacts(mode)
    wscript.echo vbCRLF & "# enumerating contact objects..." & vbCRLF
    Dim retval, objConnection, objCommand, objRecordSet
    retval = 0
    Set objConnection = CreateObject("ADODB.Connection")
    Set objCommand =   CreateObject("ADODB.Command")
    objConnection.Provider = "ADsDSOObject"
    objConnection.Open "Active Directory Provider"
    Set objCOmmand.ActiveConnection = objConnection
    objCommand.CommandText = "Select Name, displayName from 'LDAP://" & _
        LDAP_DN & "' where objectCategory='person' and objectClass='contact'"
    objCommand.Properties("Page Size") = 1000
    objCommand.Properties("Timeout") = 30
    objCommand.Properties("Searchscope") = ADS_SCOPE_SUBTREE
    objCommand.Properties("Cache Results") = False
    Set objRecordSet = objCommand.Execute
    objRecordSet.MoveFirst
    If mode = "COUNT" Then
        Do Until objRecordSet.EOF
            retval = retval + 1
            objRecordSet.MoveNext
        Loop
        wscript.echo "Contacts.....: " & retval
    Else
        Do Until objRecordSet.EOF
            wscript.echo "Contact......: " & objRecordSet.Fields("Name").Value & _
                vbTab & objRecordSet.Fields("displayName").Value
            objRecordSet.MoveNext
        Loop
    End If
End Sub

'----------------------------------------------------------------

Sub EnumGroups(mode)
    wscript.echo vbCRLF & "# enumerating security group objects..." & vbCRLF
    Dim retval, objConnection, objCommand, objRecordSet
    retval = 0
    Set objConnection = CreateObject("ADODB.Connection")
    Set objCommand =   CreateObject("ADODB.Command")
    objConnection.Provider = "ADsDSOObject"
    objConnection.Open "Active Directory Provider"
    Set objCOmmand.ActiveConnection = objConnection
    objCommand.CommandText = "Select Name, displayName from 'LDAP://" & _
        LDAP_DN & "' where objectClass='group'"
    objCommand.Properties("Page Size") = 1000
    objCommand.Properties("Timeout") = 30
    objCommand.Properties("Searchscope") = ADS_SCOPE_SUBTREE
    objCommand.Properties("Cache Results") = False
    Set objRecordSet = objCommand.Execute
    objRecordSet.MoveFirst
    If mode = "COUNT" Then
        Do Until objRecordSet.EOF
            retval = retval + 1
            objRecordSet.MoveNext
        Loop
        wscript.echo "Groups.......: " & retval
    Else
        Do Until objRecordSet.EOF
            wscript.echo "Group........: " & objRecordSet.Fields("Name").Value & _
                vbTab & objRecordSet.Fields("displayName").Value
            objRecordSet.MoveNext
        Loop
    End If
End Sub

'----------------------------------------------------------------

Sub EnumPrinters(mode)
    wscript.echo vbCRLF & "# enumerating shared printer objects..." & vbCRLF
    Dim retval, objConnection, objCommand, objRecordSet
    retval = 0
    Set objConnection = CreateObject("ADODB.Connection")
    Set objCommand =   CreateObject("ADODB.Command")
    objConnection.Provider = "ADsDSOObject"
    objConnection.Open "Active Directory Provider"
    Set objCOmmand.ActiveConnection = objConnection
    objCommand.CommandText = "Select Name, driverName, description from 'LDAP://" & _
        LDAP_DN & "' where objectCategory='printQueue'"
    objCommand.Properties("Page Size") = 1000
    objCommand.Properties("Timeout") = 30
    objCommand.Properties("Searchscope") = ADS_SCOPE_SUBTREE
    objCommand.Properties("Cache Results") = False
    Set objRecordSet = objCommand.Execute
    objRecordSet.MoveFirst
    If mode = "COUNT" Then
'        Do Until objRecordSet.EOF
'            retval = retval + 1
'            objRecordSet.MoveNext
'        Loop
        wscript.echo "Printers.....: " & objRecordSet.Count
    Else
        Do Until objRecordSet.EOF
            wscript.echo "Printer......: " & objRecordSet.Fields("Name").Value & _
                vbTab & objRecordSet.Fields("driverName").Value & _
                vbTab & objRecordSet.Fields("description").Value
            objRecordSet.MoveNext
        Loop
    End If
End Sub

'----------------------------------------------------------------

Sub EnumShares(mode)
    wscript.echo vbCRLF & "# enumerating shares..." & vbCRLF
    Dim retval, objConnection, objCommand, objRecordSet
    retval = 0
    Set objConnection = CreateObject("ADODB.Connection")
    Set objCommand =   CreateObject("ADODB.Command")
    objConnection.Provider = "ADsDSOObject"
    objConnection.Open "Active Directory Provider"
    Set objCOmmand.ActiveConnection = objConnection
    objCommand.CommandText = "Select Name from 'LDAP://" & _
        LDAP_DN & "' where objectClass='volume'"
    objCommand.Properties("Page Size") = 1000
    objCommand.Properties("Timeout") = 30
    objCommand.Properties("Searchscope") = ADS_SCOPE_SUBTREE
    objCommand.Properties("Cache Results") = False
    Set objRecordSet = objCommand.Execute
    objRecordSet.MoveFirst
    If mode = "COUNT" Then
        Do Until objRecordSet.EOF
            retval = retval + 1
            objRecordSet.MoveNext
        Loop
        wscript.echo "Shares.......: " & retval
    Else
        On Error Resume Next
        Do While Not(objRecordSet.EOF)
            wscript.echo "Share........: " & objRecordSet.Fields("Name").Value
            retval = retval + 1
            objRecordSet.MoveNext
        Loop
        wscript.echo "Shares.......: " & retval
    End If
End Sub

'----------------------------------------------------------------

Sub EnumDisabledUsers(mode)
    wscript.echo vbCRLF & "# enumerating disabled user accounts..." & vbCRLF
    Dim retval, objConnection, objCommand, objRecordSet
    retval = 0
    Set objConnection = CreateObject("ADODB.Connection")
    objConnection.Open "Provider=ADsDSOObject;"
    Set objCommand = CreateObject("ADODB.Command")
    objCommand.ActiveConnection = objConnection
    objCommand.CommandText = _
        "<GC://" & LDAP_DN & ">;(objectCategory=User)" & _
            ";userAccountControl,distinguishedName;subtree" 
    Set objRecordSet = objCommand.Execute    
    If mode = "COUNT" Then
        Do Until objRecordset.EOF
            intUAC=objRecordset.Fields("userAccountControl")
            If intUAC AND ADS_UF_ACCOUNTDISABLE Then
                retval = retval + 1
            End If
            objRecordset.MoveNext
        Loop
        wscript.echo "disabled.....: " & retval
    Else
        Do Until objRecordset.EOF
            intUAC=objRecordset.Fields("userAccountControl")
            If intUAC AND ADS_UF_ACCOUNTDISABLE Then
                wscript.echo "disabled_user: " & objRecordset.Fields("distinguishedName").Value
                retval = retval + 1
            End If
            objRecordset.MoveNext
        Loop
        wscript.echo "disabled.....: " & retval
    End If
    objConnection.Close
End Sub

'----------------------------------------------------------------

Sub ShowSpecialUsers(mode)
    wscript.echo vbCRLF & "# enumerating special user account objects..." & vbCRLF
    Dim objConnection, objCommand, objRecordSet, retval
    retval = 0
    On Error Resume Next
    Set objConnection = CreateObject("ADODB.Connection")
    Set objCommand =   CreateObject("ADODB.Command")
    objConnection.Provider = "ADsDSOObject"
    objConnection.Open "Active Directory Provider"
    Set objCommand.ActiveConnection = objConnection
    objCommand.Properties("Page Size") = 1000
    objCommand.CommandText = _
        "<LDAP://" & LDAP_DN & ">;(&(objectCategory=User)" & _
            "(userAccountControl:1.2.840.113556.1.4.803:=65536));Name;Subtree" 
    Set objRecordSet = objCommand.Execute
    objRecordSet.MoveFirst
    If mode = "COUNT" Then
        Do Until objRecordSet.EOF
            retval = retval + 1
            objRecordSet.MoveNext
        Loop
        wscript.echo "SpecialUsers.: " & retval
    Else
        Do Until objRecordSet.EOF
            wscript.echo "SpecialUser..: " & objRecordSet.Fields("Name").Value
            retval = retval + 1
            objRecordSet.MoveNext
        Loop
        wscript.echo "SpecialUsers.: " & retval
    End If
End Sub

'----------------------------------------------------------------

Sub ShowRootDSEinfo()
    wscript.echo vbCRLF & "# DOMAIN ROOT-DSE PROPERTIES" & vbCRLF
    objRootDSE.GetInfo
    For i = 0 to objRootDSE.PropertyCount - 1
        Set strProp = objRootDSE.Item(i)
        wscript.echo strProp.Name & " "
        For each strPropval in strProp.Values
           wscript.echo "  " &  strPropval.CaseIgnoreString
        Next
    Next
End Sub

'----------------------------------------------------------------
' sub: (strServer=ServerName, strSite=MySite)
'----------------------------------------------------------------

Sub ShowConnections(strServer, strSite)
    Dim objNTDSCont, objConn, confNC, objDNWithBin
    confNC = objRootDSE.Get("configurationNamingContext")
    Set objNTDSCont = GetObject("LDAP://cn=NTDS Settings,cn=" & strServer & _
        ",cn=servers,cn=" & strSite & ",cn=sites," & confNC )
    objNTDSCont.Filter = Array("ntdsConnection")
    For each objConn in objNTDSCont
       If objConn.Get("options") = 0 Then
          wscript.echo vbTab & vbTab & "connection...: " & objConn.Get("name") & " (MANUAL)"
       Else
          wscript.echo vbTab & vbTab & "connection...: " & objConn.Get("name") & " (AUTO)"
       End If
       wscript.echo vbTab & vbTab & vbTab & "enabled......: " & objConn.enabledConnection
       wscript.echo vbTab & vbTab & vbTab & "from.........: " & _

         Split(objConn.fromServer, ",")(1)
'       wscript.echo vbTab & vbTab & vbTab & "transport....: " & _

'         Split(objConn.transportType, ",")(0)
       wscript.echo vbTab & vbTab & vbTab & "cname........: " & objConn.Get("cn")
       For Each objDNWithBin In objConn.GetEx("ms-DS-ReplicatesNCReason")
           wscript.echo vbTab & vbTab & vbTab & "name_context.: " & objDNWithBin.DNString
       Next

    Next
End Sub

'----------------------------------------------------------------

Sub ShowBridgeHeadTransports(strServer, strSite)
    On Error Resume Next
    Set objServer = GetObject("LDAP://CN=" & strServer & _
        ",CN=Servers,CN=" & strSite & ","  & _
        " CN=Sites,CN=Configuration," & LDAP_DN)
    dnBHTList = objServer.GetEx("bridgeheadTransportList")
    For Each dnValue in dnBHTList
        wscript.echo vbTab & vbTab & "trn-protocol.: " & dnValue
    Next
End Sub

'----------------------------------------------------------------
' sub: (ldapPath = LDAP://OU=Sales,DC=domain,DC=com)
'----------------------------------------------------------------

Sub ShowOU_GPO_Info(ldapPath)
    On Error Resume Next
    Set objContainer = GetObject(ldapPath)
    wscript.echo vbCRLF & "# OU GPO PROPERTIES: " & ldapPath & vbCRLF
    strGpLink = objContainer.Get("gPLink")
    intGpOptions = objContainer.Get("gPOptions")

    If strGpLink <> " " Then
        'wscript.echo "gplink..: " & strGpLink
        arrGpLinkItems = Split(strGpLink,"]")
        For i = UBound(arrGPLinkItems) to LBound(arrGpLinkItems) + 1 Step -1
            arrGPLink = Split(arrGpLinkItems(i-1),";")
            strDNGPLink = Mid(arrGPLink(0),9)
            wscript.echo "gpo_link: " & strDNGPLink
            wscript.echo "gpo_name: " & GetGPOName(strDNGPLink)
            Select Case arrGPLink(1)
                Case 0
                    wscript.echo "No Override is cleared and the GPO is enabled."
                Case 1
                    wscript.echo "No Override is cleared and the GPO is disabled."
                Case 2
                    wscript.echo "No Override is checked and the GPO is enabled."
                Case 3
                    wscript.echo "No Override is checked and the GPO is disabled."
            End Select
          Next
    End If

    If intGpOptions = 1 Then
      wscript.echo "Block Policy Inheritance is checked."
    Else
      wscript.echo "Block Policy Inheritance is not checked."
    End If
End Sub

'----------------------------------------------------------------
' function: return NAME of a GPO
'----------------------------------------------------------------

Function GetGPOName(strDNGPLink)
    Set objConnection = CreateObject("ADODB.Connection") 
    objConnection.Open "Provider=ADsDSOObject;"  

    Set objCommand = CreateObject("ADODB.Command")
    objCommand.ActiveConnection = objConnection

    objCommand.CommandText = ";;distinguishedName,displayName;onelevel"
    Set objRecordSet = objCommand.Execute

    While Not objRecordSet.EOF
        If objRecordSet.Fields("distinguishedName") = strDNGPLink Then
          GetGPOName = objRecordSet.Fields("displayName")
          objConnection.Close
          Exit Function
        End If
        objRecordSet.MoveNext
    Wend
    objConnection.Close
End Function

'----------------------------------------------------------------
' sub: display security rights applied to a given OU
'----------------------------------------------------------------

Sub EnumOU_ACL(ldapPath)
    Const SE_SACL_PROTECTED = &H2000
    Const ADS_SECURITY_INFO_OWNER = &H1
    Const ADS_SECURITY_INFO_GROUP = &H2
    Const ADS_OPTION_SECURITY_MASK =&H3
    Const ADS_SECURITY_INFO_DACL = &H4
    Const ADS_SECURITY_INFO_SACL = &H8
    Set objContainer = GetObject(ldapPath)
    objContainer.SetOption ADS_OPTION_SECURITY_MASK, ADS_SECURITY_INFO_OWNER _
      Or ADS_SECURITY_INFO_GROUP Or ADS_SECURITY_INFO_DACL _
      Or ADS_SECURITY_INFO_SACL
    Set objNtSecurityDescriptor = objContainer.Get("ntSecurityDescriptor")
    intNtSecurityDescriptorControl = objNtSecurityDescriptor.Control
    wscript.echo "Auditing Tab"
    WScript.StdOut.WriteLine "Allow inheritable auditing entries from" & _
      "the parent to "
    WScript.StdOut.Write "propogate to this object and all child objects "
    If (intNtSecurityDescriptorControl And SE_SACL_PROTECTED) Then
        wscript.echo "is disabled."
    Else
        wscript.echo "is enabled."
    End If
    wscript.echo vbCRLF
    Set objSacl = objNtSecurityDescriptor.SystemAcl
    DisplayAceInformation objSacl, "SACL"
End Sub

'----------------------------------------------------------------

Sub DisplayAceInformation(SecurityStructure, strType)
    Const ADS_ACETYPE_SYSTEM_AUDIT = &H2
    Const ADS_ACETYPE_SYSTEM_AUDIT_OBJECT = &H7

    intAceCount = 0
    For Each objAce In SecurityStructure
        strTrustee = Mid(objAce.Trustee,1,12)
        If StrComp(strTrustee, "NT AUTHORITY", 1) <> 0 Then
            intAceCount = intAceCount + 1
            wscript.echo strType & " permission entry: " & intAceCount
            wscript.echo "Name: " & objAce.Trustee

            intAceType = objAce.AceType
            wscript.echo "ACETYPE IS: " & intAceType
            If (intAceType = ADS_ACETYPE_SYSTEM_AUDIT or _
                intAceType = ADS_ACETYPE_SYSTEM_AUDIT_OBJECT) Then
                WScript.StdOut.Write "Type: Success or Failure Audit"
            Else
                WScript.StdOut.Write "Audit Type Unknown."
            End If
            ReadBitsInAccessMask(objAce.AccessMask)
            wscript.echo vbCRLF
        End If
    Next
End Sub

'----------------------------------------------------------------

Sub ReadBitsInAccessMask(AccessMask)
    Const ADS_RIGHT_DELETE = &H10000
    Const ADS_RIGHT_READ_CONTROL = &H20000
    Const ADS_RIGHT_WRITE_DAC = &H40000
    Const ADS_RIGHT_WRITE_OWNER = &H80000
    Const ADS_RIGHT_DS_CREATE_CHILD = &H1
    Const ADS_RIGHT_DS_DELETE_CHILD = &H2
    Const ADS_RIGHT_ACTRL_DS_LIST = &H4
    Const ADS_RIGHT_DS_SELF = &H8
    Const ADS_RIGHT_DS_READ_PROP = &H10
    Const ADS_RIGHT_DS_WRITE_PROP = &H20
    Const ADS_RIGHT_DS_DELETE_TREE = &H40
    Const ADS_RIGHT_DS_LIST_OBJECT = &H80
    Const ADS_RIGHT_DS_CONTROL_ACCESS = &H100

    wscript.echo vbCRLF & "Standard Access Rights"
    If (AccessMask And ADS_RIGHT_DELETE) Then _
        wscript.echo vbTab & "-Delete an object."
    If (AccessMask And ADS_RIGHT_READ_CONTROL) Then _
        wscript.echo vbTab & "-Read permissions."
    If (AccessMask And ADS_RIGHT_WRITE_DAC) Then _
        wscript.echo vbTab & "-Write permissions."
    If (AccessMask And ADS_RIGHT_WRITE_OWNER) Then _
        wscript.echo vbTab & "-Modify owner."

    wscript.echo vbCRLF & "Directory Service Specific Access Rights"
    If (AccessMask And ADS_RIGHT_DS_CREATE_CHILD) Then _
        wscript.echo vbTab & "-Create child objects."
    If (AccessMask And ADS_RIGHT_DS_DELETE_CHILD) Then _
        wscript.echo vbTab & "-Delete child objects."
    If (AccessMask And ADS_RIGHT_ACTRL_DS_LIST) Then _
        wscript.echo vbTab & "-Enumerate an object."
    If (AccessMask And ADS_RIGHT_DS_READ_PROP) Then _
        wscript.echo vbTab & "-Read the properties of an object."
    If (AccessMask And ADS_RIGHT_DS_WRITE_PROP) Then _
        wscript.echo vbTab & "-Write the properties of an object."
    If (AccessMask And ADS_RIGHT_DS_DELETE_TREE) Then _
        wscript.echo vbTab & "-Delete a tree of objects"
    If (AccessMask And ADS_RIGHT_DS_LIST_OBJECT) Then _
        wscript.echo vbTab & "-List a tree of objects."

    wscript.echo vbCRLF & "Control Access Rights"
    If (AccessMask And ADS_RIGHT_DS_CONTROL_ACCESS) + _
        (AccessMask And ADS_RIGHT_DS_SELF) = 0 Then
        wscript.echo "-None"
    Else
        If (AccessMask And ADS_RIGHT_DS_CONTROL_ACCESS) Then _
          wscript.echo vbTab & "-Extended access rights."
        If (AccessMask And ADS_RIGHT_DS_SELF) Then
          wscript.echo vbTab & "-Active Directory must validate a property "
          wscript.echo vbTab & " write operation beyond the schema definition "
          wscript.echo vbTab & " for the attribute."
        End If
    End If
End Sub

'----------------------------------------------------------------

Sub EnumGPOs()
    Dim objGPM, objGPMConstants, objGPMDomain, objGPMSearchCriteria
    Dim objGPOList, objGPO
    wscript.echo vbCRLF & "# GROUP POLICY OBJECTS" & vbCRLF
    On Error Resume Next
    Set objGPM = CreateObject("GPMgmt.GPM")
    If err.Number <> 0 Then
        wscript.echo "error.......: " & _

            "GPMC is not installed, unable to enumerate group policy objects"
        Exit Sub
    End If
    Set objGPMConstants = objGPM.GetConstants()
    Set objGPMDomain = objGPM.GetDomain(ADSI_DN, "", objGPMConstants.UseAnyDC)
    Set objGPMSearchCriteria = objGPM.CreateSearchCriteria
    Set objGPOList = objGPMDomain.SearchGPOs(objGPMSearchCriteria)
    For each objGPO in objGPOList
       wscript.echo "gpo_entity...: " & objGPO.DisplayName
    Next

    wscript.echo "gpo_count...: " & objGPOList.Count

End Sub

'----------------------------------------------------------------

Sub NetlogonShare()
    Dim strDCpath, strPath, objFolder, objFile
    wscript.echo vbCRLF & "# NETLOGON SHARE CONTENTS" & vbCRLF
    strDCpath = wshShell.ExpandEnvironmentStrings("%logonserver%")
    strPath = strDCpath & "\netlogon"   
    If objFSO.FolderExists(strPath) Then
        Set objFolder = objFSO.GetFolder(strPath)
        EnumFiles strPath
        For each objSub in objFolder.SubFolders
            EnumFiles strPath & "\" & objSub.Name
        Next
    End If
End Sub

'----------------------------------------------------------------
' sub:
'----------------------------------------------------------------

Sub EnumFiles(strFolderPath)
    wscript.echo "# enumerating files in " & strFolderPath
    If objFSO.FolderExists(strFolderPath) Then
        Set objFolder = objFSO.GetFolder(strFolderPath)
        For each objFile in objFolder.Files
            wscript.echo "file_info...: " & objFile.Name & vbTab & _
                objFile.DateLastModified & vbTab & objFile.Size
        Next
    Else
        wscript.echo "error.......: unable to connect to " & strFolderPath
    End If
End Sub

Sunday, February 15, 2009

Techy Geeky News of the Week

Newsbin Pro 5.51 RC1 has been posted.  Change notes are available here.   There is also a 64-bit version now.

Like clockwork, Verizon Wireless turned on "Friends and Family" and I was able to log in and setup my list of 10 non-Verizon contacts very quickly.  So, Eric, we can blabber on without our wives threatening us about airtime minutes.

Vizio announces dumping Plasma for LCD, but then turns around and files suit against a company that sued it for infringing rights on HD technology.  And I thought the economy might slow the litigation battles down a bit.

KDE 4.3 is putting on some shiney motifness it seems.  Hmmm, looks awfully Mac-ish to me.

One of my favorite Wii games, World of Goo, is now available for Linux.

My bet is that David Merrill's Siftables will quickly be snapped up by someone like Mattel or Intel or Microsoft or who knows and be cranked out as a multi-purpose entertainment/education product.  The demonstration at TED 2009 was really cool.

Dusting Off Old Ideas to Meet the New Challenges

One thing I'm seeing a lot more lately is that companies seem to be taking bigger risks in the hopes of generating greater excitement from customers.  I see it with cars and trucks, electronic gadgets, and just starting to see it with software vendors.  Having been immersed in developer programs for some large companies in the past, I am very familiar with some of the ideas they toyed with and put on a shelf because they didn't feel the "time was right".  Some of those shelved ideas frustrated me and many others to death.  We would often "beg" for the product or feature to be released for public use, but the vendors would consult their boards and decide otherwise.

What I'm seeing now is at least an interest in going back into the brain vault and search for golden nuggets that might generate some marketing interest, and thereby generate revenue.  I cannot comment on specifics, but I've seen it with big companies, and many smaller companies as well.  There are still projects I wish they would consider pulling back out and tuning up for public release.  Most of the reasons they do not are tied to politics (business politics, not politics-politics) and partnership agreements, IP sharing agreements, antitrust risks, and so forth.

I'm really hoping that with the prolonged economic stress, that these vendors put more focus on taking risks and doing some really innovative things.  Car makers are getting a little more aggressive with shortening the gap between teasing us with concept cars to actually selling them.  I really hope that progresses to the point where they don't tease anymore and just produce it.  The only company I've seen do that at present is Apple.  They don't talk smack, until AFTER they produce a product.  And when they announce its release, it also ready for sale.  Every other vendor talks crap for months, ends up selling short on features (from those promised early on), and almost always ends the announcement with "will be available starting (insert six months from announcement date here)."   It's dumb.  Just dumb.  It's 2009.  Execution should be optimized to the point where this is not an issue.  Apple figured it out, so there's no reason everyone can't figure it out as well.  It's called business.

I'm a skeptic by nature.  At 44 I've seen so many promises fall through the cracks.  So many assurances fall apart.  Things that are widely held to be "permanent" fade, erode or morph into something entirely different.  Lao Tsu and Confuscious had a lot to say about "permanence" and they were right.  Software companies are proof of that.  So the skeptic in me says that these vendors are only testing the waters with leveraging true innovation tactics.  They will tap their creative juices just enough to measure the effect on the other end.  None of them will dive in head-first.  Not unless the economy continues to erode into a much worse condition, where they will act on desperation and that almost always gets sloppy and breaks down.

I remember working on some very interesting projects in the 90's where a well-known CAD vendor was having us play with a web-based CAD service that opened up a huge world of potential for all platforms (Windows, Apple, UNIX, Linux), but that was killed after a month of very promising reaction from participants.  I also recall working on a radically different software license control system that would have made it easier to deploy, audit, and control usage for clients inside and outside of the WAN environment.  This too was squashed in the middle of hopeful results.  I could cite many others, but with every one of these the problem was not technical but intellectual.  Usually it boiled down to potential issues with contracts, litigation, or marketing views.  Too bad.  Too bad for us and the users we support ("us" being IT and software engineering folks).  Indeed, many of these projects would be fantastic in 2009, but I seriously doubt they will see the light of day.  That's the skeptic in me again.  I'm hoping they prove me wrong.