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.

Tuesday, December 27, 2016

Fixing dns record permissions for dynamic dns

In case you have dns records that need to be changed from static to dynamic, or the machine/clusters that will be updating them have changed, you can modify the dns record permissions to allow updates.  Doing this through the gui is fine for a few records, but if you need something a bit more simple and automated, you can try this script.  It takes both the computer name (doesn't have to match the dns record, just needs to be a computer object), and the dns record (fqdn) that you are updating.  This script will work for AD dns only, and would be limited to the current domain, and likely any forest wide partitions.  If you check my article on managing other domains in powershell, you can probably get edits to other domains working on this with a few modifications and extra parameters.



param (
  $computername,
  $dnsrecord
)

$script:computernameSam = $computername + "$"

try {
  import-module activedirectory
} catch {
  write-error "This script requires the AD powershell module"
  exit
}
while ( (test-path -path Ad:) -ne $true  )
{
  start-sleep -seconds 2
}

#Standard ACL for a dynamic dns entry
  #ActiveDirectoryRights : CreateChild, DeleteChild, ListChildren, ReadProperty, DeleteTree, ExtendedRight, Delete,
  #                        GenericWrite, WriteDacl, WriteOwner
  #InheritanceType       : None
  #ObjectType            : 00000000-0000-0000-0000-000000000000
  #InheritedObjectType   : 00000000-0000-0000-0000-000000000000
  #ObjectFlags           : None
  #AccessControlType     : Allow
  #IdentityReference     : Domain\machine$
  #IsInherited           : False
  #InheritanceFlags      : None
  #PropagationFlags      : None
# 

function get-partition {
  param ( $record )
  #need to split off everything after first name to find longest zone match
  #using get-dnsserverzone ($name)
  
  $dnsrecordparts = $record.split(".")
  
  for ($i = 1; $i -lt $dnsrecordparts.length; $i++) {
    $zonenameTest = $dnsrecordparts[$i..($dnsrecordparts.length -1)] -join "."
    $zoneObj = get-dnsserverzone $zonenameTest -ea 0
    if ($zoneObj -ne $null) {
    write-output -inputobject $zoneobj
    $i = $dnsrecordparts.length + 1
    }
  }
  
}

function get-dnsobject {
  param ($record)
  $zoneObject = get-partition -record $record
  if ($zoneObject -ne $null) {
    $zonename = $zoneObject.zonename
    $record -match "(.*)(\.$zonename)"
    $dnsRecordDN = "dc=" + $matches[1] + "," + $zoneobject.distinguishedname
     try {
       get-adobject  $dnsRecordDN
    } catch { Throw "Unable to find dns record for this machine"}
  } else { throw "DNS zone not found"}
}

try {
  try {
    $guid = [guid]'00000000-0000-0000-0000-000000000000'
    $adcomputer = get-adcomputer $computername -property objectsid
    $sid = $adcomputer.objectsid
    $ctrl = [System.Security.AccessControl.AccessControlType]::Allow
    $rights = 983423
    $intype =[System.DirectoryServices.ActiveDirectorySecurityInheritance]::None
    $rule = New-Object System.DirectoryServices.ActiveDirectoryAccessRule($sid,$rights,$ctrl,$guid)
  } catch { throw "Unable to get computer account SID" }

  try {
    #find record
    $dnsDN = get-dnsObject -record $dnsrecord
  } catch { throw $_ }
  
  try {
    $acl = get-acl ad:"$($dnsDN.distinguishedname)"
    $acl.setowner([system.security.principal.ntaccount]"$script:computernameSam")
    $acl.AddAccessRule($rule)
    Set-Acl -acl $acl -path ad:"$($dnsDN.distinguishedname)"
  } catch { throw $_ }

} catch { $_}