Add to Technorati Favorites
Welcome to ThePowerShellGuy.com Sign in | Join | Help

Hey PowerShell Guy!,How Can I Map Drives Based on Membership in an Active Directory Group and a CSV file.

In this translation of a Hey Scripting guy article to PowerShell based on : How Can I Map Drives Based on Membership in an Active Directory Group When the User Belongs to Multiple Groups? I tuned the example a bit as I did not like the configuration of groups and drives in the script I moved them to a CSV file also I decided to make a general Invoke-MapNetworkdrive function first.

Let's start with the Invoke-MapNetworkdrive function :

 

Function Invoke-MapNetworkDrive ($DriveLetter,$UncPath) {
    $nw = New-Object -ComObject Wscript.Network
    $nw.MapNetworkDrive($DriveLetter, $UncPath)
}

You can see that this is wrapping the same COM object used in the Vbscript example but it is handy to have this function around in general.

Next as I wanted to use a CSV file we must make one first, you can make this in excel but from PowerShell I often use a here string to generate a test file like this :

 

$Mappings = @'
Group,Mapping
Administrators,\\localhost\c$
mowGroup,\\localhost\PoSH$
'@

Set-Content c:\scripts\mappings.csv $mappings

Now we have the helper function and CSV file we are ready to go (V2 CTP only ):

$groups = @(([AdsiSearcher]"CN=$($env:USERNAME)").Findone().properties.memberof |% {([adsi]"LDAP://$_").cn})
trap{continue};Import-Csv c:\scripts\mappings.csv |? {$groups -contains $_.group} |% {Invoke-MapNetworkDrive x: $_.mapping}

2 simple lines and we are done :)

Ok, Ok maybe some more explaination might be handy ;)

Let's go step by step over the last 2 lines and rebuild then in the console interactively :

First as in the Vbscript example we get the username not using the COM object but an environment variable:

[PoSH]>$env:USERNAME
Administrator

we make a string in "CN format"

 

[PoSH]>"CN=$($env:USERNAME)"
CN=Administrator

and Cast it into a AdsiSearcher this is new forthe PowerShell V2 CTP for Version 1.0 you need new-object directoryservices.directorysearcher("CN=$($env:USERNAME)")

[PoSH]>[AdsiSearcher]"CN=$($env:USERNAME)"

CacheResults : True
ClientTimeout : -00:00:01
PropertyNamesOnly : False
Filter : CN=Administrator
PageSize : 0
...

we start a search for a single object (use FindAll() when more objects can be returned) :

 

[PoSH]>([AdsiSearcher]"CN=$($env:USERNAME)").Findone()

Path Properties
---- ----------
LDAP://CN=Administrator,CN=Users,DC=PoshWorks,DC=com {samaccounttype, lastlogon, dscorepropagationdata, objec...

Select the Properties

[PoSH]>([AdsiSearcher]"CN=$($env:USERNAME)").Findone().properties.memberof
CN=Group Policy Creator Owners,CN=Users,DC=PoshWorks,DC=com
CN=Domain Admins,CN=Users,DC=PoshWorks,DC=com
CN=Enterprise Admins,CN=Users,DC=PoshWorks,DC=com
CN=Schema Admins,CN=Users,DC=PoshWorks,DC=com
CN=Administrators,CN=Builtin,DC=PoshWorks,DC=com

Cast the strings returned by the MemberOf property into ADSI Objects and select only the CN property

 

[PoSH]>@(([AdsiSearcher]"CN=$($env:USERNAME)").Findone().properties.memberof |% {([adsi]"LDAP://$_")})

distinguishedName : {CN=Group Policy Creator Owners,CN=Users,DC=PoshWorks,DC=com}
Path : LDAP://CN=Group Policy Creator Owners,CN=Users,DC=PoshWorks,DC=com

distinguishedName : {CN=Domain Admins,CN=Users,DC=PoshWorks,DC=com}
Path : LDAP://CN=Domain Admins,CN=Users,DC=PoshWorks,DC=com

distinguishedName : {CN=Enterprise Admins,CN=Users,DC=PoshWorks,DC=com}
Path : LDAP://CN=Enterprise Admins,CN=Users,DC=PoshWorks,DC=com

distinguishedName : {CN=Schema Admins,CN=Users,DC=PoshWorks,DC=com}
Path : LDAP://CN=Schema Admins,CN=Users,DC=PoshWorks,DC=com

distinguishedName : {CN=Administrators,CN=Builtin,DC=PoshWorks,DC=com}
Path : LDAP://CN=Administrators,CN=Builtin,DC=PoshWorks,DC=com

[PoSH]>@(([AdsiSearcher]"CN=$($env:USERNAME)").Findone().properties.memberof |% {([adsi]"LDAP://$_").cn})
Group Policy Creator Owners
Domain Admins
Enterprise Admins
Schema Admins
Administrators
[PoSH]>

we put this result into the $Groups variable and are ready for the next line :

get the contents of the CSV file

[PoSH]>Import-Csv c:\scripts\mappings.csv

Group Mapping
----- -------
Administrators \\localhost\c$
mowGroup
\\localhost\PoSH$

Filter the groups from the user

 

[PoSH]>Import-Csv c:\scripts\mappings.csv |? {$groups -contains $_.group}

Group Mapping
----- -------
Administrators
\\localhost\c$

 

We feed this to the Invoke-MapNetworkdrive function and the Trap will break the Loop when the Driveletter is allready mapped and will break the loop so the first mapping "Wins" as in the VbScript example

trap{continue};Import-Csv c:\scripts\mappings.csv |? {$groups -contains $_.group} |% {Invoke-MapNetworkDrive x: $_.mapping}

Enjoy,

Greetings /\/\o\/\/

Published Friday, December 14, 2007 7:32 PM by MoW

Comments

# Interesting Finds: December 15, 2007

Saturday, December 15, 2007 10:39 AM by Jason Haley

# re: Hey PowerShell Guy!,How Can I Map Drives Based on Membership in an Active Directory Group and a CSV file.

Looks great, but I'm having some trouble replicating under certain situations. My primary account on a dev box  contains a . (it's first.last) and using both the ADSI accelerator and the directory searcher yield no results.  I could easily get around this using a simple if statement and a split("."), but is there a more direct way?

Sunday, December 16, 2007 12:26 AM by justin.stokes

# re: Hey PowerShell Guy!,How Can I Map Drives Based on Membership in an Active Directory Group and a CSV file.

Justin,

I think you can escape the dot with a backslash in the ADSI search

Greetings /\/\o\/\/

Sunday, December 16, 2007 5:33 PM by MoW

# re: Hey PowerShell Guy!,How Can I Map Drives Based on Membership in an Active Directory Group and a CSV file.

I looked at this a bit more and I think this will work no matter what the name is (also it's v1 friendly):

$user = ((New-Object System.DirectoryServices.DirectorySearcher("(&(objectCategory=User)(samAccountName=$env:USERNAME))")).FindOne()).Properties.memberof|% {([adsi]"LDAP://$_").cn}

It's not very pretty, but it works :)

-Justin

Monday, December 17, 2007 4:53 PM by justin.stokes
Anonymous comments are disabled