Friday, March 23, 2012

AD Powershell module and managing multiple domains

One of the things I have noticed every time I try using the Microsoft AD powershell commandlets is that they are not very multi-domain friendly. Most of the commandlets have a -server option where you can point to a server. To do this dynamically, you need to discover a DC with Get-ADDomainController first. However, today I was thinking it would be nice to update permissions cross domain with get-acl/set-acl. Unfortunately, there is no -server option here. From the examples I have seen for managing AD permissions with these two, it uses the AD: PSdrive that gets created when the ActiveDirectory Module is loaded. This default drive points to the domain that your machine is a member of, so this may not be helpful. If you try to use get-acl with this drive and point to a distinguishedName in another domain you will see an error like this:

Get-Acl : A referral was returned from the server

Since AD: is a PSDrive, there is no reason you can't add some more for other domains. Lets say you have two domains, contoso.com and child.contoso.com

New-PSDrive -Name "Child" -Root "" -PsProvider ActiveDirectory -server (Get-ADDomainController -domain child.contoso.com -discover -writable).name

This will create a PSDrive called Child:, which will reference this domain. So to work with get-acl you can reference child:"objectdn" to get the acl. For other commandlets, set-location child: and try using these to access objects in it.

If you wanted to auto-create a drive for every domain in your forest you could do this easily (though a bit slowly). PSDrive names are limited in that they cannot contain '.', so in this example I'm just stripping a domain's first portion of its name out:

(get-adforest).domains|foreach {$temp = $_.substring(0,$_.indexof('.')); New-PSDrive -Name $temp -Root "" -PsProvider ActiveDirectory -server (Get-AD
DomainController -domain $_ -discover -writable).name}


Update:

After trying to work with the Microsoft AD powershell module for this, and having a lot of problems in a mixed 2008/2003 multidomain environment, I ran into the BSonPosh module. This has a much simpler way of reading and writing ACL's in AD which looks like it will run very easily in a multidomain environement, or non-2008 AD domain. I have a extension to the module to Decode AD ACL.

Wednesday, March 21, 2012

Checking NIC for collisions (speed/duplex mismatch) Windows Powershell

This is an old powershell v1 script that I came up with quite a long time ago. I'm sure it can be modified for easier and more robust usage. Since network card settings in the registry can be difficult to decode between vendors, the best way to look for speed/duplex issues is looking at collisions. Microsoft systems are not very details on networking errors, but they do keep track of this type of problem and it is available WMI. The script below pieces together two WMI classes to get the speed setting and looks for collisions.

Results in PSObject array of all NIC's
Computername        NicName                       LinkSpeed          Collisions
------------        -------                       ---------          ----------
MyComputer          Intel(R) PRO/100...                 100                   0


function get-NicError ([string]$server) {
 #This function uses WMI queries against the target machine to get link speed information and
 #check for any recorded network collissions.  It combines the two queries to print out collisions
 #per adapter with link speed.

 if ([string]::IsNullOrEmpty($server)) {
  write-host -foregroundcolor "yellow"  "Usage: get-NicError servername"
  write-host -foregroundcolor "yellow"  "   Get speed and collision details for network adapters"
  return
 }

 $result = @()

 $a = gwmi -namespace root\wmi -class msndis_ethernetmoretransmitcollisions -computername $server |select-object instancename,ndisethernetmoretransmitcollisions
 $b = gwmi -namespace root\wmi -class msndis_linkspeed -computername $server | select-object instancename,ndislinkspeed 

 if (($a -eq $null) -or ($b -eq $null)) {
  write-error "WMI connection error"
  return 
 }

 foreach ($link in $b) {
  $link.ndislinkspeed = $link.ndislinkspeed / 10000
 }

 foreach ($item in $a) {
   foreach ($seconditem in $b) {
    if ($item.instancename -eq $seconditem.instancename) {
      $myres = New-Object psobject
     Add-Member -InputObject $myres NoteProperty Computername $server
     Add-Member -InputObject $myres Noteproperty NicName $item.instancename
     Add-Member -InputObject $myres Noteproperty LinkSpeed $seconditem.ndislinkspeed
     Add-Member -InputObject $myres Noteproperty Collisions $item.ndisethernetmoretransmitcollisions
     $result += $myres
    }
   }
 }

 return $result
   
}