Monday, July 31, 2017

Testing connectivity to your domain controller

In the distant past there was a useful client side tool for checking connectivity between clients and domain controllers (netdiag.exe). According to microsoft's command line reference guide, it is available in windows 8 and 2012, but in reality the command does not exist on any windows machine I have checked beyond 2003. Trying to run an older version won't work either due to some incompatibility. So, alternatives are required to do checks. One thing you would typically want to check between a client and a domain controller is port connectivity.  Below, I will show a simple script that tests most of the ports.  Some may not be open in your environment (like 636,3269 for ldaps).  Some ports are dynamic, so I haven't included trying to check these.

To begin with, you should know what domain controller your workstation has logged into.  This machine logon establishes the "secure channel" between your machine and the domain.  You can use an old tool that is still around called nltest. 

C:\Windows>nltest /sc_query:contoso.com
Flags: 30 HAS_IP  HAS_TIMESERV
Trusted DC Name \\DC1.contoso.com
Trusted DC Connection Status Status = 0 0x0 NERR_Success
The command completed successfully
This output shows the status of your secure channel, and the name of the domain controller you are querying.  You will need to provide the name of the domain you are connected to.  FQDN domain name or NETBIOS domain name should work fine.

This script will provide two functions, one port checker and one function to run to test your connection.  Run Test-DomainControllerPorts with your domain name (or leave it blank for auto detect).  The script returns the name of the DC that you are connected to, along with 2 arrays of ports that are open and another of ports that aren't responding.

function tcpt ([string]$serv, [string]$p) {
 $result = $false
 try {
  $conn = new-object system.net.sockets.tcpclient($serv,$p)
  if ($conn.connected) { $result = $true } else { result = $false }
  $conn.close()
 } catch {
  $result =  $false
 }
 $conn = $null
 return $result
}
function test-DomainControllerPorts {
 param (
  $domainname = (gwmi win32_computersystem).domain
 )
 $secureChannelDC = (nltest /sc_query:$domainname |
  where {$_ -match "Trusted DC Name"}).split("\\") |
  where {$_ -match $domainname}
 $secureChanneldc = $securechanneldc.trim()
 $functionalports = @()
 $nonFunctionalPorts = @()
 $portsToCheck = ("53", "88", "137", "139", "389", "445", "464", "3268", "636", "3269")
 foreach ($port in $portsToCheck) {
  $portstat = tcpt $secureChannelDC $port
  if ($portstat) {
   $functionalports += $port
  } else {
   $nonfunctionalPorts += $port
  }
 }
 $result = new-object PSObject
 add-member -inp $result NoteProperty DomainController $secureChannelDC
 add-member -inp $result NoteProperty OpenPorts $functionalports
 add-member -inp $result NoteProperty UnOpenPorts $nonfunctionalports
 out-default -inp $result
}

Sunday, July 2, 2017

AD: Simple way to remove all members of a group

No loops required, use the -clear parameter in set-aduser.

Set-adgroup -identity "name of group" -clear member

The time required to execute will vary depending on number of people in the group.

Saturday, May 6, 2017

Some of my coding on Github

1) From Columbia AI course assignment for search algorithms, n-puzzle solver in python 3.  My first attempt at python programming.
2) From Columbia AI course assignment in CSP's, suduko solver using AC3 and backtracking, written in Python3.
3) Arabic typing website code.  (Live site at: http://makinghijrah.com/arabic-typing/)

Wednesday, April 19, 2017

Download all enterprise CA crl's from active directory

This script will look for all published crl's in the configuration partition, download them, and write them to binary files.  To further examine the files, you can open them up in windows (standard certificate viewing tools), or use the PSPKI module to dig into the data.


$debase = new-object directoryservices.directoryentry("LDAP://RootDSE")
$configpartition = $debase.configurationNamingContext[0]
$de = new-object directoryservices.directoryentry(` "LDAP://CN=CDP,CN=Public Key Services,CN=Services," + $configpartition)
$ds = new-object directoryservices.directorysearcher($de)
$ds.filter = "(objectclass=cRLDistributionPoint)"
$ds.propertiestoload.add("certificaterevocationlist")|out-null
$crls = $ds.findall()
foreach ($crl in $crls) {
$CAcert = $crl.path.replace("LDAP://CN=","")
$CAcert = $CAcert.substring(0,$CAcert.indexof(","))
$file = $CACert + ".crl"
set-content $file  ([byte[]]($crl.properties.certificaterevocationlist[0])) ` -encoding Byte
}

Download all files from IIS web directory listing (non-recursive)

This simple code should be able to dig out all file names from inside the A HREF tags where the file name consists of letters, numbers, a few special characters, spaces, file path forward slashes and periods; and ends with an extension of 2-4 characters.  Each entry will be downloaded, however, take note that the A HREF data will contain a relative path to the item, including the directory structure.  The webclient downloadfile method's second parameter wants a path name, including file name, for the destination.  If the full path doesn't exist, the file may just get put in the current directory.

$wc = new-object net.webclient

$sitename = "http://somesite/somedirectory"

$weblisting = $wc.downloadstring($sitename)

$items = select-string '"[a-zA-Z0-9/._-() ]*\.[a-zA-Z0-9]{2,4}"' `
   -input $weblisting -allmatches|
   foreach {$_.matches.value.replace('"','')}



foreach ($item in $items) {

 $wc.downloadfile($sitename + $item, ".\" + $item)

}

Wednesday, March 29, 2017

Password change failed: Configuration information could not be read from the domain controller, either because the machine is unavailable, or access has been denied

This error was recently brought to my attention when a user was trying to change password after the expiration notice at logon. This was the first time I had seen it so I thought it was a bit odd. Based on the text of the error message alone, you would expect that the domain controller can't be contacted at all, there is some secure trust issue, or some weird issue on the domain controller. Typically when domain connectivity problems occur, you will get messages like domain controller unavailable or trust relation type problems. Searching around google comes up with some answers that don't seem to relevant, such as unjoin/rejoin the machine. One thing to look at is multi domain environments. Is the machine they are accessing on a different domain that the domain where the account exists? Is the trust one way or two way? Is the connectivity restricted between the two domains (dmz's)? In my particular case, the password change was being attempted on a trusting domain (one way) with limited access. Check this article to help determine possible connectivity requirements.

Monday, March 20, 2017

OpenSuse upgrade to leap 42.2 - missing nvidia module

Last week, my old desktop was running leap 42.1 and I decided to run a normal zypper update to get the latest packages. Even though all my repos were pointing to 42.1, it gave me "opensuse" as a package to update along with the 3.5+GB of files that needed to be downloaded for a distro update. This machine has been through every version of opensuse from 10.3 until leap 42.1 with continual distro updates. Each time there is some small problem, usually with grub pointing to invalid boot locations, audio not working or nvidia module issues. In this case, the updates ran fine, reboot to a failed graphic environment and command prompt logon. After the update all the repos were still pointing to 42.1, so I updated everything, including nvidia, to point to 42.2 locations. I ran another update, had to download a few hundred more GB of files. Reboot again and failed to load the GUI. Running startx gave the missing nvidia module error. I tried playing around with different versions of the drivers, changing from G03 to 02 and 04, but no luck there. I downloaded the driver compatible with my card (340) from nvidia's site. That said the driver was already installed and my attempt to continue installing anyways come up with some compile fails and module failed to build. So I went back to yast and messed around with the nvidia packages some more. In the install process, I noticed in the nvidia installer file name (visible in a progress bar) that after the 340.102 driver version there was a k4.4.27_2 which looks like a kernel version. Checking to see what I was currently running showed an old 4.1.15-8 version. This was the latest grub was showing despite having at least 6 newer kernels installed on the system. The latest kernel on the machine, 4.4.49-16 didn't work with nvidia either, so I worked on grub to get the 4.4.27-2 kernel loading as default and everything was working after that. So it looks like the current nvidia packages only support up to this version, so the system needs to be a bit behind what is the latest model.

Tuesday, January 17, 2017

powershell: filtering for unique lines of csv

Scenario: You have a large csv file (several hundred meg or more) representing username to computer name mappings.  The data contains a lot of duplicates as it represents activity over a period of time.  The data is already sorted by time, so how do you get the most recent activity per computer while ignoring the rest?

Pipeline method with commandlets:

import-csv .\data.csv| select -Unique computername|ConvertTo-Csv -NoTypeInformation
 |out-file .\filtered-data.csv

This ran for hours, hit several hundred MB of ram usage and eventually had to be cancelled as it was taking too long.  Unfortunately for the unique filtering on select, it had to do csv conversions to get the attribute that I wanted to filter on.


Hackish method with hash table:

$ht = new-object hashtable

function selective-add {
 [CmdletBinding()]
   param ( [Parameter(Mandatory=$True,ValueFromPipeline=$True)]$line )
   begin {}
   process {
     $data = $line.split(',')
     if ($ht.contains($data[1])) {} else {
       $ht.add($data[1],$data[0])
     }
   }
}

get-content .\data.csv | selective-add
$ht.keys | % { add-content -path filtered-data.csv -value $("{0},{1}" -f $_, $ht.Item($_)) }

This only took about 15 minutes, however it sucked up twice as much ram as the previous method in a very short period of time.