Register a SA Forums Account here!
JOINING THE SA FORUMS WILL REMOVE THIS BIG AD, THE ANNOYING UNDERLINED ADS, AND STUPID INTERSTITIAL ADS!!!

You can: log in, read the tech support FAQ, or request your lost password. This dumb message (and those ads) will appear on every screen until you register! Get rid of this crap by registering your own SA Forums Account and joining roughly 150,000 Goons, for the one-time price of $9.95! We charge money because it costs us money per month for bills, and since we don't believe in showing ads to our users, we try to make the money back through forum registrations.
 
  • Post
  • Reply
Nebulis01
Dec 30, 2003
Technical Support Ninny

kampy posted:

Have you tried with LastWriteTime instead of CreationTime? It may be that the CreationTime does not reflect the correct date for whatever reason, I'd recommend checking the attributes for the incorrectly matched files with

code:
select fullname, creationtime, lastwritetime
in place of the Remove-Item part.

It looks like something is touching the files and while the directories are named by date created the file timestamps are today so I've got a bit of work to figure out what's touching these that shouldn't be. But that would solve the issue.

Adbot
ADBOT LOVES YOU

Swink
Apr 18, 2006
Left Side <--- Many Whelps
Thanks guys. This is working perfectly.

Siets
Sep 19, 2006

by FactsAreUseless
So I'm working on a pretty standard script for creating network shares. Designed to do everything. Order of functions is:

1. User supplies name of a group.
2. Name is used to generate an AD group based on the name.
3. A series of directories are created on the share based on the name.
4. NTFS permissions of the directories are modified based on the AD group that was made in step 2.

Pretty standard stuff, but here is where it gets interesting. Our campus is pretty large and leverages multiple domain controllers. The script works fast enough such that it submits the AD group creation (in step 2) to one domain controller, but then later on in step 4 it will sometimes fail to change NTFS permissions when calling for the same AD group. This is because, I think, it is hitting up a different domain controller for information and the AD group data updates haven't converged yet. I emailed our DC admins and they said that convergence tends to float around a minute or more.

Rather than sleep my script for a minute or more, I'm trying to come up with a clever way to have the ACL modification step continually retry the DCs until it gets the AD group data it needs to successfully modify the NTFS permissions. For reference, here is my current ACL mod code snippet:

code:
    If ($dirAclApply -eq 1) {
        $dirAcl = Get-Acl "$Drive\$groupID\OUTBOX"
        $dirAcl.AddAccessRule($ruleRead)
        $dirAcl.AddAccessRule($ruleMod)
        $dirAcl | Set-Acl "$Drive\$groupID\OUTBOX"
        Write-Host -Fore Green "Applied folder ACL modification"
        }
Again, pretty standard. It grabs the ACL, then uses the AddAccessRule method to apply rule objects that I whipped up earlier in the script.

What I'm thinking might work for this is to wrap up my $dirAcl.AddAccessRule($rule) methods inside of a Try-Catch that itself is nested inside a Do-While loop based around ending at non-detection of an error. Then I can set $ErrorActionPreference to "SilentlyContinue" and be on my merry way. Problem is, I'm pretty new to error handling (bad, I know) and would just like some outside ideas on a cleanly way to do this. Is there a better way than my Try-Catch / Do-While idea? I'm pretty open.

kampy
Oct 11, 2008

Siets posted:

1. User supplies name of a group.
2. Name is used to generate an AD group based on the name.
3. A series of directories are created on the share based on the name.
4. NTFS permissions of the directories are modified based on the AD group that was made in step 2.

What I'm thinking might work for this is to wrap up my $dirAcl.AddAccessRule($rule) methods inside of a Try-Catch that itself is nested inside a Do-While loop based around ending at non-detection of an error. Then I can set $ErrorActionPreference to "SilentlyContinue" and be on my merry way. Problem is, I'm pretty new to error handling (bad, I know) and would just like some outside ideas on a cleanly way to do this. Is there a better way than my Try-Catch / Do-While idea? I'm pretty open.

Are you using New-ADGroup from the ActiveDirectory module to create your group initially? If you are, you could do something like:

code:
$group = New-ADGroup -PassThru @and_the_rest_of_your_variables_as_before

#and sample rule to illustrate:
$write = [System.Security.AccessControl.FileSystemRights] "Write"
$inheritance = [System.Security.AccessControl.InheritanceFlags] "ContainerInherit, ObjectInherit"
$propagation =  [system.security.accesscontrol.PropagationFlags] "None"
$access = [System.Security.AccessControl.AccessControlType] "Allow"

$rule = New-Object System.Security.AccessControl.FileSystemAccessRule($group.sid, $write, $inheritance, $propagation, $access)
$group.SID will contain the SID of the newly made group, which you can then use when you create your $ruleRead and $ruleMod variables. Then you should be able to apply the rules instantly without needing to wait for the group to propagate everywhere.

Also when doing try-catch, don't set $ErrorActionPreference, use -ErrorAction with the command instead, that way you will not accidentally let errors fail silently in places where you don't want them to.

Siets
Sep 19, 2006

by FactsAreUseless

kampy posted:

... -PassThru

Hah, this is beautiful. Yep I'm using New-ADGroup and the AddAccessRule method was taking string input from my rule and having to go out and get it from the domain controllers. Passing it off the output this way seems much smarter. Thanks!

kampy posted:

Also when doing try-catch, don't set $ErrorActionPreference, use -ErrorAction with the command instead, that way you will not accidentally let errors fail silently in places where you don't want them to.

Yeah good call. I have heavily debugged the script to where this is pretty much my last issue (famous last words), but this is a better practice in principle that I need to adopt going forward. I guess I just have too much of a penchant for really pretty output windows with lots of green text that I generated. :3:

edit: vvv The idea behind the Do-While was to have it continue trying to add the permissions until it got the AD group data successfully from one of the domain controllers that had updated with the new information. The While condition would be While ( there are error messages happening ), and as soon as the command succeeds, the loop would end since there wouldn't have been an error that time.

Does Try-Catch repeat the command over and over on its own? Again, I haven't played much with Try-Catch and would like to learn more about proper error handling. The last I tried using it, it wasn't able to catch the right error and just did nothing for me. I think I need to learn more about the $error variable array and also how to tell Catch specifically what I am looking to catch.

Siets fucked around with this message at 17:20 on Jul 5, 2012

adaz
Mar 7, 2009

You don't need to wrap it in a Do-While loop, a simple Try/Catch is enough. I mean, a do/while loop will probably just infinitely repeat as the same error is happening over and over again (on SEt-ACL my guess on your two most common errors are going to be path not found/available and permissions denied -- those aren't "fixable" without adding an additional function or something).

adaz
Mar 7, 2009

Siets posted:

edit: vvv The idea behind the Do-While was to have it continue trying to add the permissions until it got the AD group data successfully from one of the domain controllers that had updated with the new information. The While condition would be While ( there are error messages happening ), and as soon as the command succeeds, the loop would end since there wouldn't have been an error that time.

A better idea would be to create the group on that specific DC where the folder is going to be rather than just waiting for the 15 minutes or whatever your AD replication topology is setup to be for it to show up there. I mean, you don't want the user hanging for minutes while it just sits there and retries.

The thing is, what you are trying to do isn't really proper error handling. You already know what the problem is going to be (group not on DC) so you should really code a way to make that not happen rather than bandage over it with some try/catch stuff.

Siets
Sep 19, 2006

by FactsAreUseless

kampy posted:

Also when doing try-catch, don't set $ErrorActionPreference, use -ErrorAction with the command instead, that way you will not accidentally let errors fail silently in places where you don't want them to.

Ok, for the life of me I can't get this to actually work.

If I set the $ErrorActionPreference variable to SilentlyContinue at the start of the script, it works to suppress my Get-ADGroup command that is designed to simply test if the group I am making already exists. (Most of the time, I am expecting this command to fail since I am using the script to create new groups. I wanted it there just in case I was running the script and someone else had already made something without updating me. Whether it fails or not, it writes to the host letting the user know either way, so the failure to get the group is by design here and I want it to appear as such when running.)

I tried running Get-ADGroup with -ErrorAction SilentlyContinue at the end, but it still spits out a giant ugly blob of red text that I don't care about and don't want anyone else to care about. Does this only work inside of Try Catch blocks? Maybe that's my issue here. Is my syntax just wrong, or does $ErrorActionPreference cover a wider range of functions than -ErrorAction being set individually?

edit: Yep, tried it within a Try Catch Finally block and I guess it only works inside that context. Nevermind, false alarm.

Siets fucked around with this message at 17:52 on Jul 6, 2012

Doctor Malaver
May 23, 2007

Ce qui s'est passé t'a rendu plus fort
I have another Powershell book opening for review in a couple of days: Learn Windows PowerShell Scripting and Toolmaking in a Month of Lunches - by Don Jones and Jeffrey Hicks. If you are interested in reviewing it, check out the main thread.

gwon
Sep 11, 2001

Dr. Duck says "NO!"
Hey all, I'm trying to use powershell to save myself some time, but I'm looking for a bit of advice.

I'm trying to give a single user access to a batch of mailboxes in exchange 2003.

This flat command works perfectly through powershell:

code:
[PS] C:\>add-mailboxpermission -Identity "user.mailbox" -User "test.adminaccount" -AccessRights FullAccess
(When this command completes, it shows me a table of the change it has made)

So, I'm trying to script it so that I can feed a csv file with a list of a few hundred users and then do this as a batch job.

The script looks like this:

code:
# Adds "Full Access Rights" to all mailboxes in "mailboxes.csv" for user specified after -User
Import-CSV c:\mailboxes.csv | Foreach-Object -process {
$Id = $_.Identity
Add-MailboxPermission -Identity "$Id" -User "craig.errington" -AccessRights FullAccess
}
With this script saved directly on the exchange server, on the root of C:\ - with the mailboxes.csv file right beside it also on the root of C:\ on the same server.

Running the script through the exchange shell doesn't feed back any error message, but nothing seems to happen to the mailbox.. And nothing shown on screen to state that anything has been done.

Any ideas what I'm doing wrong?

gwon
Sep 11, 2001

Dr. Duck says "NO!"
Reply to myself.

The CSVs I had created: I hadn't given the category headers for the lines in the CSV properly. With correctly formed CSV file, this worked great.

adaz
Mar 7, 2009

gwon posted:

Reply to myself.

The CSVs I had created: I hadn't given the category headers for the lines in the CSV properly. With correctly formed CSV file, this worked great.

I found this out like 5 years ago and I still forget to do it on occasion. The error message could be more helpful :argh:

Doctor Malaver
May 23, 2007

Ce qui s'est passé t'a rendu plus fort

Doctor Malaver posted:

I have another Powershell book opening for review in a couple of days: Learn Windows PowerShell Scripting and Toolmaking in a Month of Lunches - by Don Jones and Jeffrey Hicks. If you are interested in reviewing it, check out the main thread.

Bumping this because I didn't have target audience described until now:

“Microsoft administrators (not developers, not DBAs) with an intermediate level of PowerShell experience. Not complete newcomers. No coding experience is needed, although a background in scripting will not hurt. Not a PowerShell expert, unless they understand that this is not intended as a comprehensive expert-level book nor as an exhaustive reference.”

angrytech
Jun 26, 2009
Alright, I'm using a DirectorySearcher to return a list of computer accounts from AD. Is there a way to figure out the last date that these accounts were modified on?

kampy
Oct 11, 2008

angrytech posted:

Alright, I'm using a DirectorySearcher to return a list of computer accounts from AD. Is there a way to figure out the last date that these accounts were modified on?

They have a whenChanged property you can use. Sample:

code:
$root = [ADSI] ''
$searcher = New-Object System.DirectoryServices.DirectorySearcher($root)
$searcher.filter = "(&(sAMAccountName=*`$))"
$test = $searcher.FindAll()
foreach ($comp in $test) { $comp.properties.whenchanged }

adaz
Mar 7, 2009

angrytech posted:

Alright, I'm using a DirectorySearcher to return a list of computer accounts from AD. Is there a way to figure out the last date that these accounts were modified on?

You can also use USN property (unique to each DC) if you're trying to do something like "retrieve the accounts that have been changed since the last time I ran this". Just make sure to query the same DC each time

angrytech
Jun 26, 2009
Ok new problem.
I've got a string that looks like this:
code:
'$variable blahblahblah somestuff "powershell is really pissing me off"'
How can I get access the content of $variable? I've tried
code:
'"$variable" blahblahblah somestuff "powershell is really pissing me off"'
as well as using backticks and parentheses but that doesn't work.


edit: I guess what I'm asking is if there's any way to evaluate a variable within a single quoted string?

angrytech fucked around with this message at 19:09 on Jul 30, 2012

Mario
Oct 29, 2006
It's-a-me!
Do you have to single quote the string instead of escaping the double quotes with backticks? Single quoted strings are not supposed to do variable expansions.
code:
"$variable blahblahblah somestuff `"powershell is really pissing me off`""

Jelmylicious
Dec 6, 2007
Buy Dr. Quack's miracle juice! Now with patented H-twenty!
Just to explain what Mario is saying here: Single quotes take everything as written, while double quotes interpret everything written. Backticks make thing that would be interpreted literal again. To illustrate:
code:
PS C:\> $var = 5
PS C:\> "$var"
5
PS C:\> '$var'
$var
PS C:\> "`$var"
$var
PS C:\> '`$var'
`$var
Notice in the last one that the backtick is also simply written out.

kampy
Oct 11, 2008
String formatting is what you'll want to use in single quote strings:

code:
$var = 5
'It is: "{0}"' -f $var

Powerful Two-Hander
Mar 10, 2004

Mods please change my name to "Tooter Skeleton" TIA.


I've been trying to put together a web monitoring script as we have an application that ocasionally seems to keep its services running (so looks like it's working) but becomes inaccessible. I think this is due to a domain binding problem so have currently set the service to restart once a week to force it to re-authenticate, but ideally I'd like to monitor the website for it directly and only do this if there's an actual problem.

I was trying to use System.net.httpwebrequest to do this but get 401 errors returned and I can't figure out (because I literally know nothing about what I'm doing and just copy poo poo I find on technet - this may well be the problem here) how to get the existing session credentials sent through to pass authentication. The user account it's running from has access to the site and I thought that by default -usecurrentcredentials is set to true so it shold work. I'd really like to avoid having to specify a username and password in the script as it's just one more thing to have to change if the password ever gets modified.

Is there something obvious/easy I'm missing here?

kampy
Oct 11, 2008

Powerful Two-Hander posted:

I was trying to use System.net.httpwebrequest to do this but get 401 errors returned and I can't figure out (because I literally know nothing about what I'm doing and just copy poo poo I find on technet - this may well be the problem here) how to get the existing session credentials sent through to pass authentication. The user account it's running from has access to the site and I thought that by default -usecurrentcredentials is set to true so it shold work. I'd really like to avoid having to specify a username and password in the script as it's just one more thing to have to change if the password ever gets modified.

Is there something obvious/easy I'm missing here?

Yeah, kind of. Usedefaultcredentials is false by default, so you'll need to set it to true.

code:
$req = [System.Net.HttpWebRequest]::Create("https://companyweb.whatever")
$req.UseDefaultCredentials = $true
$res = $req.GetResponse()

stubblyhead
Sep 13, 2007

That is treason, Johnny!

Fun Shoe

kampy posted:

Yeah, kind of. Usedefaultcredentials is false by default, so you'll need to set it to true.

code:
$req = [System.Net.HttpWebRequest]::Create("https://companyweb.whatever")
$req.UseDefaultCredentials = $true
$res = $req.GetResponse()

Correct, see here. To be clear, this will use the same credentials as whatever user is running the script, so make sure whatever is running it (scheduled task, background service, whatever) has the authorization to do what's necessary.

Powerful Two-Hander
Mar 10, 2004

Mods please change my name to "Tooter Skeleton" TIA.


kampy posted:

Yeah, kind of. Usedefaultcredentials is false by default, so you'll need to set it to true.

code:
$req = [System.Net.HttpWebRequest]::Create("https://companyweb.whatever")
$req.UseDefaultCredentials = $true
$res = $req.GetResponse()

Well poo poo, I guess I wasn't copying poo poo from Technet as well as I thought! Thanks for pointing out my lack of reading skills! :)

Edit: And yes, it'll be running as a scheduled task with valid credentials specified so that should work.

Drumstick
Jun 20, 2006
Lord of cacti
Google has failed me. Im trying to add existing users to a security group. However all my googling has turned up is adding members through csv. Set-adgroup seems to do everything but add members.

Im tried add-adprincipalgroupmembership but its requesting an identity. Here is what I have


$ou = [adsi] "Ldap://<path>"
foreach ($user in $ou) {
add-adprincipalgroupmembership -MemberOf "cn=group,dc=domain,dc=local"
}

When run it prompts for an identity. So I stuck in a -identity $user after the cmdlt. Then I get an error saying Cannot bind paramater Identity. cannot convert system.directoryservices.directoryentry value of type system.directoryservices.directoryentry to type Microsoft.ActiveDirectory.management.adprincipalgroupmembership.


Im sure im missing something glaringly obvious.

adaz
Mar 7, 2009

http://technet.microsoft.com/en-us/library/ee617203 says that the identity parameter requires distinguished name (DN), GUID, security identifier (SID), or SAM account name

But to be more specific

code:
$ou = [adsi] "Ldap://<path>"
foreach ($user in $ou.children) {
    add-adprincipalgroupmembership -MemberOf "cn=group,dc=domain,dc=local" -identity $user.distinguishedName
}

skipdogg
Nov 29, 2004
Resident SRT-4 Expert

That is way more elegant than what I was going to suggest. I was going to suggest getting a list of all users by doing a get-aduser and pulling their sAMAccountName then pumping that into the foreach statement.

kampy
Oct 11, 2008
Since you can pipe objects to Add-ADPrincipalGroupMembership, you could also do something like this:

code:
Get-ADUser -Filter * -SearchBase "OU=Test,DC=domain,DC=local" | Add-ADPrincipalGroupMembership -MemberOf "CN=group,DC=domain,DC=local"
e: using -Filter {objectClass -eq "user"} is also redundant with Get-ADUser

kampy fucked around with this message at 19:32 on Aug 8, 2012

Drumstick
Jun 20, 2006
Lord of cacti
Ah, thank you so much.

"That is way more elegant than what I was going to suggest. I was going to suggest getting a list of all users by doing a get-aduser and pulling their sAMAccountName then pumping that into the foreach statement."

This was one thing I had considered, but it seemed like so much more effort then what was needed.

Im not as familiar with using powershell in that way kampy. It seems like every so often a problem comes up and I know powershell is capable of handling it in a much easier fashion. I have a hard time distinguishing when to use that form(?) over the one I posted.

stubblyhead
Sep 13, 2007

That is treason, Johnny!

Fun Shoe

Drumstick posted:

Im not as familiar with using powershell in that way kampy. It seems like every so often a problem comes up and I know powershell is capable of handling it in a much easier fashion. I have a hard time distinguishing when to use that form(?) over the one I posted.

As an object lesson, let's look at the example kampy used. Look at the online help for Get-ADUser (Get-Help Get-ADUser -full). Just before the list of examples, it says its output type is Microsoft.ActiveDirectory.Management.ADUser. If there's a lot of these, it'll just be an array of ADUser objects instead of only one.

Now look at the help for Add-ADPrincipalGroupMembership. Under the -Identity parameter, ADUser is listed as a valid input type. It also says that it accepts pipeline input, which means we can run the first command, pipe it into the second, and it will automatically act on each object one at a time.

Functionally there's no difference between doing
code:
$users = Get-ADUser -Filter * -Searchbase "foo"
Foreach ($user in $users) {
  Add-ADPrincipalGroupMembership -MemberOf "bar" -Identity $user
}
and what kampy did; kampy's way is just more concise and easier to read once you get your legs under you. Let's pretend for a second that we wanted to add a single user into a bunch of groups, though. The -MemberOf parm doesn't take pipeline input, so you would need to do a foreach or similar to add the user to all your groups.

kampy
Oct 11, 2008

stubblyhead posted:

Functionally there's no difference between doing
code:
$users = Get-ADUser -Filter * -Searchbase "foo"
Foreach ($user in $users) {
  Add-ADPrincipalGroupMembership -MemberOf "bar" -Identity $user
}
and what kampy did; kampy's way is just more concise and easier to read once you get your legs under you. Let's pretend for a second that we wanted to add a single user into a bunch of groups, though. The -MemberOf parm doesn't take pipeline input, so you would need to do a foreach or similar to add the user to all your groups.

As it turns out, there is a small difference between my example and using a foreach as above.

Both ways work identically when adding users from an OU to a group as long as none of the users is a member of said group. However if one of the users fetched by Get-ADUser is already a member of the group, none of the users will get added when passing the user objects through a pipeline.

Assuming I read the Trace-Command logs correctly, it looks like Add-ADPrincipalGroupMembership passes all the users on to Add-ADGroupMember in a single call which then raises an exception if one of the users has previously been added, causing none of the users to be added. Since the foreach loop ends up calling Add-ADGroupMember individually, exceptions are raised for the users that are members already and the rest are correctly processed.

So pipelines can be effective, but they don't always end up doing what you expect. Testing with multiple scenarios is important :)

stubblyhead
Sep 13, 2007

That is treason, Johnny!

Fun Shoe

kampy posted:

Both ways work identically when adding users from an OU to a group as long as none of the users is a member of said group. However if one of the users fetched by Get-ADUser is already a member of the group, none of the users will get added when passing the user objects through a pipeline.

Are you sure that is correct? The way I understand it, only one object gets passed from the pipeline at a time, so the cmdlet wouldn't have any notion that there were other objects, much less that some were already in the security group. It doesn't look like -Identity even accepts an array as input.

Jelmylicious
Dec 6, 2007
Buy Dr. Quack's miracle juice! Now with patented H-twenty!
I believe that if you have an array and the next command accepts an array as input, it will just pass it as one thing. Not sure though.

kampy
Oct 11, 2008

stubblyhead posted:

Are you sure that is correct? The way I understand it, only one object gets passed from the pipeline at a time, so the cmdlet wouldn't have any notion that there were other objects, much less that some were already in the security group. It doesn't look like -Identity even accepts an array as input.

Yep, that's the way it works with PowerShell 2.0 on Server 2008 R2 in any case. It's not the way I would expect piping objects to work either, but I assume it's by design because according to help Add-ADPrincipalGroupMembership it will use a single AD operation to do it's business.

stubblyhead
Sep 13, 2007

That is treason, Johnny!

Fun Shoe

stubblyhead posted:

Are you sure that is correct? The way I understand it, only one object gets passed from the pipeline at a time, so the cmdlet wouldn't have any notion that there were other objects, much less that some were already in the security group. It doesn't look like -Identity even accepts an array as input.

OK, a little more detail now that I've had a chance to experiment and refresh my memory a bit. Passing an array in by pipeline will hit the function all at once, but it will run the PROCESS block once for each object instead of only a single time if it were passed as a parameter. Take the following:
code:
function Do-Stuff {
    [cmdletbinding()]
    param(
        [Parameter (ValueFromPipeline = $True)]
        [string]$things)

    BEGIN{
        Write-Output "begin block"
    }

    PROCESS{
        Write-Output "process block"
        foreach ($thing in $things) {
            Write-Output $thing
        }
    }

    END{
        Write-Output "end block"
    }
}
If you ran this as "a","b","c" | Do-Stuff, you'd get out

begin block
process block
a
process block
b
process block
c
end block

Trying to do Do-Stuff -things "a","b","c" would throw an error because it can't take an array of strings in that parameter. If we did allow that, our output would be
begin block
process block
a
b
c
end block

I guess it is possible that the cmdlet has some functionality in the BEGIN block that would halt if any of the users were already in the target group, but that would be a really bizarre thing to do IMO.

FISHMANPET
Mar 3, 2007

Sweet 'N Sour
Can't
Melt
Steel Beams
Alright, powershell is pissing me off right now.

I created a bunch of accounts with a python script that called dsadd, but I hosed it up and now I'm trying to fix the profile paths. I want to find all the profile paths that are on server2, instead of server1.

So I say to myself, this sounds perfect for Powershell! Except Powershell can't read the profile paths out of most of my accounts, they just show up as null. dsget works just fine, and looking at them in AD Users & Computers I see the bad profile path, but get-aduser shows nothing.

Nevermind what a loving task it was to get powershell to even search. And nevermind how impossible Microsoft has made it to actually get the AD cmdlets. Why in the hell would I have to run a special instance of Powershell (Active Directory Module for Windows PowerShell) to actually be able to query AD. Shouldn't running Powershell on the DC be enough?

adaz
Mar 7, 2009

This is why the AD modules are rear end and never use them, use the raw .net code. At least, that's my opinion because you never know what machine might or might not have that module installed.

This will always work - I assume you mean profile paths not terminal services profile paths which are entirely different beasts and a super big pain in the rear end to search on no matter what you're using. Thanks Terminal Services team!


code:
$root = [ADSI] "LDAP://yourdc.yourdomain.com"
$searcher = New-Object System.DirectoryServices.DirectorySearcher $root
 # * = wildcard in LDAP search syntax
$searcher.filter = "(&(objectCategory=person)(objectClass=user)(profilepath=*yoursearchfilter*))"
$users = $searcher.FindAll()

foreach($user in $users) {
	$deObj = $user.GetDirectoryEntry()
	$deObj.ProfilePath = "newprofilepath"
	$deObj.psbase.commitchanges()

}
Now if you're talking about terminal services home directory you're going to have to do the filtering on the client side. And we can't just do an LDAP filter search because the terminal services teams sucks and didn't properly integrate their poo poo into AD so we have to do a filter to see if the property is available and set on the user. If it is, then we can do the check in the script itself.

code:
$root = [ADSI] "LDAP://yourdc.yourdomain.com"
$searcher = New-Object System.DirectoryServices.DirectorySearcher $root
$searcher.filter = "(&(objectCategory=person)(objectClass=user)(userParameters=*CtxWFHomeDirDrive*))"
$users = $searcher.FindAll()

foreach($user in $users) {
	$deObj = $user.GetDirectoryEntry()
	$termPath = $deObj.psbase.invokeget("TerminalServicesHomePath")
	if($termPath -match "somecriteria") {
		$deObj.psbase.invokeset("terminalserviceshomepath","whatever")
		$deObj.psbase.commitchanges()
	}

}


Nebulis01
Dec 30, 2003
Technical Support Ninny

FISHMANPET posted:

Alright, powershell is pissing me off right now.

I created a bunch of accounts with a python script that called dsadd, but I hosed it up and now I'm trying to fix the profile paths. I want to find all the profile paths that are on server2, instead of server1.

So I say to myself, this sounds perfect for Powershell! Except Powershell can't read the profile paths out of most of my accounts, they just show up as null. dsget works just fine, and looking at them in AD Users & Computers I see the bad profile path, but get-aduser shows nothing.

Nevermind what a loving task it was to get powershell to even search. And nevermind how impossible Microsoft has made it to actually get the AD cmdlets. Why in the hell would I have to run a special instance of Powershell (Active Directory Module for Windows PowerShell) to actually be able to query AD. Shouldn't running Powershell on the DC be enough?

Curious, if you have time would you spin up a Server 2012 DC in test and see if the query succeeds in powershell v3? It's supposed to have improved/fixed a bunch of this poo poo

FISHMANPET
Mar 3, 2007

Sweet 'N Sour
Can't
Melt
Steel Beams

Nebulis01 posted:

Curious, if you have time would you spin up a Server 2012 DC in test and see if the query succeeds in powershell v3? It's supposed to have improved/fixed a bunch of this poo poo

I'll see if I can give it a try, as long as I don't need to put it into DNS, because AD doesn't control DNS, we have to go to the dark overlords to get SRV records put in.

Adbot
ADBOT LOVES YOU

stubblyhead
Sep 13, 2007

That is treason, Johnny!

Fun Shoe

FISHMANPET posted:

I'll see if I can give it a try, as long as I don't need to put it into DNS, because AD doesn't control DNS, we have to go to the dark overlords to get SRV records put in.

It can be installed on 2008 also, so if you have a sandbox environment already you could just put it on there.

  • 1
  • 2
  • 3
  • 4
  • 5
  • Post
  • Reply