Tuesday, November 25, 2014

Resize User Photos and Import them into Active Directory Accounts


Resize User Photos and Import them into Active Directory Accounts using PowerShell and ImageMagick.

This script looks in a specified path for photos named with the EmployeeID attribute of the users in a specified OU, resizes the images to the correct size and then writes the images into the thubnailPhoto attribute of the users Active Directory account.

As always, no responsibility is accepted for it's use.

 param([string]$searchbase , [string]$imagepath)  
 #Import the ActiveDirectory PowerShell module  
 import-module ActiveDirectory  
 #Check for Mandatory Parameters  
 if (!$searchbase)  
      {  
      write-output 'Usage: ADImages {searchbase} {imagepath}'  
      write-output 'eg. ADImages "OU=Staff,OU=Users,DC=orgname,DC=com,DC=au" \\fileserver\Userimages'  
      exit  
      }  
 if (!$imagepath)  
      {  
      write-output 'Usage: ADImages {searchbase} {imagepath}'  
      write-output 'eg. ADImages "OU=Staff,OU=Users,DC=orgname,DC=com,DC=au" \\fileserver\Userimages'  
      exit  
      }  
 #Check if the Searchbase exists  
 $OUCheck = [adsi]::Exists("LDAP://$($searchbase)")  
 if ($OUCheck -eq "True")   
      {  
      write-output "Found Searchbase $($searchbase)"  
      }  
 else  
      {  
      write-output "Searchbase $($searchbase) not found"  
      exit  
      }  
 #Check that the Image Path exists  
 $ImageCheck = Test-Path $imagepath  
 if ($ImageCheck -eq "True")  
      {  
      write-output "Found Image Path $($imagepath)"  
      }  
 else  
      {  
      write-output "Image Path $($imagepath) not found"  
      exit  
      }  
 #Check for the ImageMagick Conversion Tool  
 $ToolCheck = Test-Path ".\ImageMagick\convert.exe"  
 if ($ToolCheck -eq "True")  
      {  
      write-output "ImageMagick tool found"  
      }  
 else  
      {  
      write-output "ImageMagick tool not found. Download from http://www.imagemagick.org/"  
      exit  
      }  
 #Create the Thumbnail directory if it doesn't exist  
 $DirCheck = Test-Path ".\ADThumbs"  
 if ($DirCheck -eq "True")  
      {  
      write-output "Thumbnail directory already exists"  
      }  
 else  
      {  
      write-output "Creating Thumbnail directory"  
      New-Item -ItemType directory -Path .\ADThumbs  
      }  
 #Get an array of users from the Searchbase  
 $UserList = Get-ADUser -Filter * -SearchBase $searchbase  
 Foreach ($User in $UserList)  
      {  
      #Get the EmployeeID Attribute  
      $EmpID = Get-ADUser -Filter * -SearchBase $User -Properties employeeID | select -expand employeeID  
      write-host "Looking for Employee Photo for User $($User) with ID $($EmpID)"  
      #Tests to see if the UserImages file exists  
      $FileCheck = Test-Path "$($imagepath)\$($EmpID).jpg"  
      if ($FileCheck -eq "True")   
           {  
           #Retrieves JPG files of the target user from the UserImages share  
           $jpgfile = "$($imagepath)\$($EmpID).jpg"  
           $newjpgfileName = ".\ADThumbs\$($EmpID)-AD.jpg"  
           write-output "Scaling $($jpgfile) to $($newjpgfileName)"  
           .\ImageMagick\convert $jpgfile -thumbnail 96 -gravity center -crop 96x96+0-15 +repage -strip $newjpgfileName   
           #Write the thumbnail photo back to the AD user Account  
           $photo = [byte[]](Get-Content $newjpgfileName -Encoding byte)  
           Set-ADUser $User -Replace @{thumbnailPhoto=$photo}  
           }  
      else  
           {  
           #User Image file not found  
           write-output "Employee ID $($EmpID) not found in $($imagepath)"  
           }  
      }  

Monday, February 10, 2014

File Path manipulation in Excel

Saw this over at stackoverflow. Had to make a note of it for future reference.

http://stackoverflow.com/questions/18617349/excel-last-character-string-match-in-a-string


Let's say for example you want the right-most \ in the following string (which is stored in cell A1):
Drive:\Folder\SubFolder\Filename.ext
To get the position of the last \, you would use this formula:
=FIND("@",SUBSTITUTE(A1,"\","@",(LEN(A1)-LEN(SUBSTITUTE(A1,"\","")))/LEN("\")))
That tells us the right-most \ is at character 24. It does this by looking for "@" and substituting the very last "\" with an "@". It determines the last one by using
(len(string)-len(substitute(string, substring, "")))\len(substring)
In this scenario, the substring is simply "\" which has a length of 1, so you could leave off the division at the end and just use:
=FIND("@",SUBSTITUTE(A1,"\","@",LEN(A1)-LEN(SUBSTITUTE(A1,"\",""))))
Now we can use that to get the folder path:
=LEFT(A1,FIND("@",SUBSTITUTE(A1,"\","@",LEN(A1)-LEN(SUBSTITUTE(A1,"\","")))))
Here's the folder path without the trailing \
=LEFT(A1,FIND("@",SUBSTITUTE(A1,"\","@",LEN(A1)-LEN(SUBSTITUTE(A1,"\",""))))-1)
And to get just the filename:
=MID(A1,FIND("@",SUBSTITUTE(A1,"\","@",LEN(A1)-LEN(SUBSTITUTE(A1,"\",""))))+1,99)
However, here is an alternate version of getting everything to the right of the last instance of a specific character. So using our same example, this would also return the file name:
=TRIM(RIGHT(SUBSTITUTE(A1,"\",REPT(" ",99)),99))

Sunday, May 19, 2013

Memory Leak in Windows 8 Network Data Usage Monitoring Driver

Just thought I'd share this experience I had over the weekend, as it may save someone else many hours of troubleshooting.

I've been tinkering around with Windows 8 at home, even though I know there's little likelihood that we'll implement it at work any time soon.

While using my Windows 8 machine to copy a large amount of files from my NAS to a USB drive, I was experiencing lock-ups of my system. It wasn't a complete crash. The system would just become extremely unresponsive.

It soon became apparent that something was leaking memory. I was seeing the amount of memory being consumed skyrocket up to 100%, at which point the copy process would crash and system would stop responding politely. The task manager and performance monitor were not attributing the memory to any process however.

I tried using robocopy instead of Explorer copy. Same thing.

I tried updating the Realtek network driver, USB 3 driver and even the ASUS BIOS, (as they were all a few versions behind). Same thing.

I was getting to the point where I was figuratively scratching my head, so I tried booting into safe mode with networking. Aha! The memory usage stayed consistent and the copy performed just fine!

There are a number of network related drivers that safe mode don't load. DriverView showed that one of them is the Windows Network Data Usage Monitoring Driver ndu.sys that was introduced in Windows 8 and provides "network data usage monitoring functionality".

Disabling this driver by changing the start value to 4 in HKLM\SYSTEM\CurrentControlSet\Services\Ndu 
solved the problem.

Maybe this will be fixed when Microsoft releases Blue.

Monday, December 3, 2012

Using ICACLS to Grant Permissions on Folders

It took me a little while to work this out because I found the documentation here a little confusing and multiple interpretations of it seem to be floating around the net.

My goal was to grant a group permissions to access a folder, modify the subfolders and files within it, but not have the ability to modify the folder itself in any way. A pretty common requirement right? You would think some administrator somewhere would have come up with a clear set of instructions on how to do it, but I couldn't find any definitive answer that did quite what I wanted. Eventually, I figured out what I was doing wrong and scripted it myself.

So, the answer is:

icacls "Folder Path" /grant:r "AuthenticationRealm\GroupOrUser":(OI)(CI)(IO)(D,RC,S,AS,GR,GW,GE,RD,WD,AD,REA,WEA,X,DC,RA)

icacls "Folder Path" /grant "AuthenticationRealm\GroupOrUser":(RC,S,AS,GR,GE,RD,WD,AD,REA,X,DC,RA)

The first command replaces [/grant:r] any existing permissions for the GroupOrUser on all Subfolders and files only of the Folder Path and all of it's contents that inherit [(OI)(CI)(IO)] without forcing inheritance, and grants everything except Change permissions and Take ownership rights.

The second command grants GroupOrUser permissions to the Folder Path itself, but grants only those permissions that allow the GroupOrUser to be able to create files/folders and write data. They are not able to delete or modify the folder.

The permissions list in the first command can be modified to give Read Only access or Write Only (Dropbox) style access. If you're doing dropbox style access, it's sometimes a good idea to give the special identity CREATOR OWNER extra permissions so that submitters can modify their own work and it can also be a good idea to use Access-based Enumeration so that submitters cannot see other users submissions that may be in the same share.

There's probably a better way to do this in Powershell, but I haven't discovered it yet.




Monday, October 17, 2011

Enumerating Indirect Group Memberships

A colleague asked me yesterday if I knew how to get a list of all direct AND indirect group memberships that a user had. He wanted to use this to estimate the Kerberos token size for users with large numbers of group memberships as this can cause access problems if it exceeds set limits.

I vaguely remembered that I had something like this in a script I wrote to enumerate the members of a group both directly and indirectly. It uses the functionality of the Remote Server Administration Tools. There's also a hotfix to correct the output. I dug out the script and revised it to provide what he required.

In its simplest form, the command to run is:


dsget user <fulldn> -memberof -expand

For example:

dsget user "CN=testuser,OU=Staff,DC=company,DC=com" -memberof -expand

This will provide a list of group memberships in fulldn format. To simplify it to SAM group names you can pipe the output to another dsget command for the groups:

dsget user <fulldn> -memberof -expand | dsget group -samid

You can also simplify the input if you pipe in the dsquery command for the user:

dsquery user -samid <samid> | dsget user -memberof -expand | dsget group -samid

For example:

dsquery user -samid testuser | dsget user -memberof -expand | dsget group -samid 


Edit: You can use the same technique to list the members of a group:
dsquery group -samid <Groupname> | dsget group -members | dsget user -samid -fn -ln
Also, be wary of pasting one of these command strings in Outlook, as it has the tendency to automatically change hyphens to the longer "dash", which is an invalid character if you copy it out of Outlook and paste it to the command prompt.

Monday, September 19, 2011

DNS Suffix Search Order via DHCP

I was recently working on a new parallel domain with one of the members of my team and the issue of DNS Suffix Search Order came up. The search order had to be set to include the parallel domain, the primary domain and a number of other things.

I was adamant that the search order could be set by DHCP as well as by GPO, but I couldn't specifically remember the details. My engineer pointed me to this Microsoft Knowledge Base article that states:
The following methods of distribution are not available for pushing the domain suffix search list to DNS clients:
  • Dynamic Host Configuration Protocol (DHCP). You cannot configure DHCP to send out a domain suffix search list. This is currently not supported by the Microsoft DHCP server.
Fortunately, an engineer from another department came to the rescue with DHCP Option 135. This can be added in Windows Server 2008 as follows (I believe this originated in a TechNet post):

1. On the 2008 Server running DHCP, open the DHCP MMC.
2. Expand DHCP and choose the DHCP server name.
3. Right click on IPv4
4. Choose "Set Predefined Options"
5. Click on Add.
6. Name: "Domain suffix search order"
Data Type: String
Code: "135" (without the quotation marks)
Description: "List of domain suffixes in order" (without the quotation marks)
String: enter your search suffixes separated by comma with no spaces

sample1.com.au,sample2.net,sample3.org

7. Click onto the OK to save changes .
8. Exit the DHCP MMC and restart the DHCP Server Service.
9. Open the DHCP MMC again and now scope option 135 is a listed option.






Monday, March 21, 2011

Reverse DNS

I recently had a guy ask me how he could fix a corrupt reverse DNS.

Simple enough, I thought and proceeded to instruct him how to change the AD Integrated DNS zone to a "Standard Primary" DNS zone, then take the DNS file, import it into Excel and manipulate the data however he wanted. He could then just put the file back and reload the DNS zone and that's that.

I also told him how he could use DNSCMD to export the DNS data from an AD Integrated zone.:
dnscmd /ZoneExport FQDN_of_zonename Zone_export_file

He then started telling me he had problems locating the reverse DNS information and it was at this point my techie sense started tingling. He may not even have a reverse DNS zone (it is completely optional, but can be quite useful), or may actually be referring to his DNS resolver cache. (I haven't determined the answer yet).

Reverse DNS operates just like regular DNS, but instead of looking up an IP address using a hostname, you look up the hostname from the IP address. This can be very useful in easily determining which host is the source or destination of traffic, instead of finding the port on the local switch.

Reverse DNS zones use the network address in reverse notation and the suffix in-addr.arpa. So if your network's IP Schema is based on subnets of the private range 172.16.0.0, you could have a reverse DNS zone of 16.172.in-addr.arpa, which could contain entries for all hosts within all subnets on your network. Of course, if you have an extremely large network, you probably want to break this down further, such as 10.16.172.in-addr.arpa, etc.

So, if your host server.company.com has an (A) record of 172.16.10.99, he can have a pointer DNS record type (PTR) in the reverse DNS zone of 99.10.16.172.in-addr.arpa pointing back to its designated hostname of server.company.com.

Reverse DNS zones for IPv6 use the special zone ip6.arpa and store their loooong IPv6 addresses as a sequence of nibbles in reverse order in much the same way as the IPv4 addresses are stored in reverse order. So an IPv6 address of 2001:0db8:85a3::62cd will be stored as a PTR record as d.c.2.6.0.0.0.0.3.a.5.8.8.b.d.0.1.0.0.2.ip6.arpa.

A DNS resolver cache on a caching name server will resolve a query, even though they are not authoritative for the result, by making a query to the authoritative server on behalf of the client. The caching name server will then store this record for it's Time-To-Live (TTL) in a local cache. This will result in quicker resolutions and reduced load on Internet name servers. A corrupted resolver cache can simply be cleared and it will rebuild itself with use.