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
MJP
Jun 17, 2007

Are you looking at me Senpai?

Grimey Drawer

adaz posted:

I don't use the AD cmdlets so this code might nto work but what you want to do is when you grab your users pipe them through Select-Object and grab the property you want, like CN or DN. then send that list to the Create-Uilist. When the list returns with the user's they have selected iterate through, bind to their AD object and perform whatever operation you want.

code:

$users =  get-aduser -filter * -searchbase "OU=Non-IT Users,OU=ATL,DC=subdomain,DC=domain,DC=com" | select-Object {$_.cn}

Create-UiList -Title "This is a test." -ChoiceQuestion "Pick an Option" -Choices $users

if($result) {
	foreach($user in $result) {
		# Grab user off CN/DN and perform operation requested here.
	}

}


I copied that into a .ps1 file and ran it in Powershell. Got the following error output (OU name and username were changed as needed, so it looks like that component is good to go)

code:
PS U:\> C:\Users\mjp\Desktop\DisplayUsers.ps1
The term 'Create-UiList' is not recognized as the name of a cmdlet, function, s
cript file, or operable program. Check the spelling of the name, or if a path w
as included, verify that the path is correct and try again.
At C:\Users\mpfeffer\Desktop\DisplayUsers.ps1:4 char:14
+ Create-UiList <<<<  -Title "This is a test." -ChoiceQuestion "Pick an Option"
 -Choices $users
    + CategoryInfo          : ObjectNotFound: (Create-UiList:String) [], Comma
   ndNotFoundException
    + FullyQualifiedErrorId : CommandNotFoundException

PS U:\>

MJP fucked around with this message at 15:51 on Nov 19, 2012

Adbot
ADBOT LOVES YOU

AreWeDrunkYet
Jul 8, 2006

I'm trying to mess around with permissions, and I'm stuck on removing a user from a bunch of ACLs.

This is the meat of what I'm using:
code:
$acl = get-acl "directory"
foreach($access in $acl.access){if ($access.identityreference -eq "NT Authority\Authenticated Users"){$acl.RemoveAccessrule($access)}}
set-acl "directory" $acl
I've tried this with both removeaccessrule and removeaccessruleall, and traced the script to make sure that the method is being called. The only thing that happens is that removeaccessrule returns "True" while removeaccessruleall is silent - neither removes the rule for Authenticated Users.

What am I doing wrong?

kampy
Oct 11, 2008

AreWeDrunkYet posted:

What am I doing wrong?

Your script works fine, so I assume the rules you're trying to remove are inherited? If that's the case, they can not be directly removed from a subdirectory. You'd have to remove them from the source or remove inheritance from the subdirectory and copy over the rules you want to keep.

AreWeDrunkYet
Jul 8, 2006

kampy posted:

Your script works fine, so I assume the rules you're trying to remove are inherited? If that's the case, they can not be directly removed from a subdirectory. You'd have to remove them from the source or remove inheritance from the subdirectory and copy over the rules you want to keep.

That may end up being something I need to address later, but I believe I'm running into an issue before I even attempt to apply permissions. If I run the first two lines then display $acl.access, the entry for Authenticated users is still on the list with unchanged rights.

Or is the problem that $access.IsInherited is True for Authenticated Users, which prevents the removeaccessrule method from removing the rule from $acl?

Mully Clown
Aug 1, 2004

I handle my piss like the great big frilly girls blouse that I am
I would recommend having a look at the NTFSSecurity module. I use it a to track down orphaned SIDs. Probably helpful for what you're after as well.

gbeck
Jul 15, 2005
I can RIS that

MJP posted:

So am I looking at this as a possible script:

code:
\\servername\c$\tools\delprof2 /c:\servername /p

$x = [array]$excludeUsers = "Citrix","admin","Track"
$profiles = get-Childitem C:\users -directory  -exclude $excludeUsers
$y = Delete inactive profiles on 'Servername'? (Yes/No) #Say Y to start the process
  if ($x) {Write-Host "N"} #Say N since this account should never be deleted
  elseif {Write-Host "Y"} #say Y to delete all other accounts not specified in $x 

Are the servers 2008+? If so you can use WMI instead of delprof to remove the profiles.

code:
foreach($profile in (Get-WmiObject -Class Win32_UserProfile))
{
    if($profile.LocalPath -notmatch 'administrator')
    {
        Write-Host $profile.LocalPath
        #$profile.Delete()
    }
}

MJP
Jun 17, 2007

Are you looking at me Senpai?

Grimey Drawer

MJP posted:

I copied that into a .ps1 file and ran it in Powershell. Got the following error output (OU name and username were changed as needed, so it looks like that component is good to go)

code:
PS U:\> C:\Users\mjp\Desktop\DisplayUsers.ps1
The term 'Create-UiList' is not recognized as the name of a cmdlet, function, s
cript file, or operable program. Check the spelling of the name, or if a path w
as included, verify that the path is correct and try again.
At C:\Users\mpfeffer\Desktop\DisplayUsers.ps1:4 char:14
+ Create-UiList <<<<  -Title "This is a test." -ChoiceQuestion "Pick an Option"
 -Choices $users
    + CategoryInfo          : ObjectNotFound: (Create-UiList:String) [], Comma
   ndNotFoundException
    + FullyQualifiedErrorId : CommandNotFoundException

PS U:\>

Sorry to continue harping on this, but I did some research and couldn't quite find a native PS cmdlet to do this - there's a Scripting Guy entry about making an .hta to find it but I'm supposed to do this in one file alone.

Anyone?

kampy
Oct 11, 2008

MJP posted:

Sorry to continue harping on this, but I did some research and couldn't quite find a native PS cmdlet to do this - there's a Scripting Guy entry about making an .hta to find it but I'm supposed to do this in one file alone.

Anyone?

Judging from the error message you do not have the custom function Create-UiList that adaz posted copypasted in your DisplayUsers.ps1 or if you do, it is below the code that tries to execute it and therefore it can not be found. Either way you'll want to go and fix your script so that the function is correctly created above the $users line, go get it from:

adaz posted:

code:
#################
# Create-UIlist #
#################
# ..snip..

Wicaeed
Feb 8, 2005
So this is kind of a stupid question:

Company has a need to sign executable files with a cert and time stamp from verisign.

This is handled by a relatively simple command line command, but it requires the use of a Windows SKD CMD Shell.

Ideally, I would like to create a script that I can use to simply drag an executable to be signed over, and have poweshell work it's magic.

I'm having a devil of a time finding out how to really DO this, however.

Tips/Hints?

stubblyhead
Sep 13, 2007

That is treason, Johnny!

Fun Shoe

Wicaeed posted:

So this is kind of a stupid question:

Company has a need to sign executable files with a cert and time stamp from verisign.

This is handled by a relatively simple command line command, but it requires the use of a Windows SKD CMD Shell.

Ideally, I would like to create a script that I can use to simply drag an executable to be signed over, and have poweshell work it's magic.

I'm having a devil of a time finding out how to really DO this, however.

Tips/Hints?

I'm pretty sure dropping things like that is equivalent to running
code:
c:\scripts\myScript.ps1 c:\files\myfile.exe
I'm not sure if that really answers your question though, but if you can write a script that'll do whatever needs to be done using that syntax on the command line, you should be good.

GPF
Jul 20, 2000

Kidney Buddies
Oven Wrangler

Wicaeed posted:

So this is kind of a stupid question:

Company has a need to sign executable files with a cert and time stamp from verisign.

This is handled by a relatively simple command line command, but it requires the use of a Windows SKD CMD Shell.

Ideally, I would like to create a script that I can use to simply drag an executable to be signed over, and have poweshell work it's magic.

I'm having a devil of a time finding out how to really DO this, however.

Tips/Hints?
There's a builtin variable called $args that holds any arguments you pass to a running script. Here's a tiny program to test and show arguments.

code:
Write-Host "Num Args:" $args.Length;
foreach ($arg in $args)
{
  Write-Host "Arg: $arg";
}
Try making that, saving it to your desktop, then drop your executable on the shortcut and see what it says.

edit: Grr...neither the ps1 nor the shortcut want to take an executable as a drag-drop. Quick and dirty, I'd have them drop the executable into a folder, have the script step through the files in there, do the signing magic, then move them somewhere else.

GPF fucked around with this message at 17:58 on Nov 29, 2012

Titan Coeus
Jul 30, 2007

check out my horn
In that situation, you can make a batch script that accepts the drag and drop, and have that pass the command line argument to the power shell script.

See http://stackoverflow.com/questions/2819908/drag-and-drop-to-a-powershell-script

Titan Coeus fucked around with this message at 20:36 on Nov 29, 2012

Wicaeed
Feb 8, 2005

Titan Coeus posted:

In that situation, you can make a batch script that accepts the drag and drop, and have that pass the command line argument to the power shell script.

See http://stackoverflow.com/questions/2819908/drag-and-drop-to-a-powershell-script

I actually read that exact post on Stack Overflow and tried it, but for some reason whenever I drag and drop a file the batch script seems to die as it is passing the entire file contents instead of just the path to the powershell script :confused:

MJP
Jun 17, 2007

Are you looking at me Senpai?

Grimey Drawer
Okay, so I'm taking the whole shpiel about needing to create a dropdown list of users a bit simpler. What I'm trying to do now is simply just get a working array of users. I've got the format of the individual cmdlets correct but I simply can't for the life of me figure out how to make one array with input from multiple cmdlets.

Here's what I have thus far using this link to convert output to an array: http://blogs.msdn.com/b/powershell/archive/2009/02/27/converting-to-array.aspx

code:
###### Imports AD module

import-module ActiveDirectory

###### ToArray should pipe the output of a command to an array named at the start of each command

function ToArray
{
  begin
  {
    $output = @(); 
  }
  process
  {
    $output += $_; 
  }
  end
  {
    return ,$output; 
  }
}

###### Get all users in an OU and sorts them by lastname, firstname

$users = get-aduser -filter * -searchbase "OU=Company Managed Users08,OU=ATL,DC=company,DC=companyname,DC=com" | Ft Surname, Givenname -a | ToArray $Users +=
$users = get-aduser -filter * -searchbase "OU=Company Managed Users08,OU=BOS,DC=company,DC=companyname,DC=com" | Ft Surname, Givenname -a | ToArray $Users +=
When I enter $Users I get an array of the BOS OU. Eventually I'll be doing this for a whole bunch of sites so I figure this would be a good starter step for what I need to do.

I saw somewhere that the $users += command was supposed to add to an existing array. I'm not sure if I've got the syntax wrong or placement of the +=, or if it just needs to go somewhere else.

Any thoughts?

Jelmylicious
Dec 6, 2007
Buy Dr. Quack's miracle juice! Now with patented H-twenty!
Didn't really look over your code, but your += is definitely in the wrong place. The following statements are the same:
code:
$a = $a + $b 
$a += $b
+= is just a shortcut for: add something to my variable and make that the new variable.

MJP
Jun 17, 2007

Are you looking at me Senpai?

Grimey Drawer
Okay, so I think I got it - the syntax to add to an array is like this:

code:
$arrayname = @(Your entire cmdlet goes here) 
$arrayname += @(The second cmdlet from which you want to pipe output goes here)
$arrayname += @(The third cmdlet goes here)
When I did my get-aduser cmdlets like this I was finally able to get the two OUs of users in one array, huzzah!

code:
$users = @(get-aduser -filter * -searchbase "OU=Company Managed Users08,OU=ATL,DC=company,DC=companyname,DC=com" | Ft Surname, Givenname -a | ToArray 
$users += @(get-aduser -filter * -searchbase "OU=Company Managed Users08,OU=BOS,DC=company,DC=companyname,DC=com" | Ft Surname, Givenname -a | ToArray 
So my next question: how do I sort them alphabetically by surname? The bottom of this site specifies just doing something like $users = $users | Sort-Object. The cmdlet runs without error but when I enter $users, I get this:

The object of type "Microsoft.PowerShell.Commands.Internal.Format.FormatEndData" is not valid or not in the correct sequence. This is likely caused by a user-specified "format-*" command which is conflicting with the default fo
rmatting.
+ CategoryInfo : InvalidData: (:) [out-lineoutput], InvalidOperationException
+ FullyQualifiedErrorId : ConsoleLineOutputOutOfSequencePacket,Microsoft.PowerShell.Commands.OutLineOutputCommand

For reference, here's my code thus far including the now successful array adds and now-failing alphabetical sort:

code:
###### Imports AD module

import-module ActiveDirectory

###### ToArray establishes the ability to pipe output to an array but it doesn't seem to do what we need in a multiple cmdlet environment, so it's just used now to clear any previous $users array

function ToArray
{
  begin
  {
    $users = @(); 
  }
  process
  {
    $users += $_; 
  }
  end
  {
    return ,$users; 
  }
}

###### Get all users in an OU and sorts them by lastname, firstname

ToArray

$users = @(get-aduser -filter * -searchbase "OU=Segal Managed Users08,OU=ATL,DC=segal,DC=segalco,DC=com" | Ft Surname, Givenname -a)
$users += @(get-aduser -filter * -searchbase "OU=Segal Managed Users08,OU=BOS,DC=segal,DC=segalco,DC=com" | Ft Surname, Givenname -a)
$users + sort-object

evil_bunnY
Apr 2, 2003

Get-ChildItem, if I see you around I'm going to beat your rear end to a pulp. That is all.

evil_bunnY fucked around with this message at 21:56 on Dec 12, 2012

ZeitGeits
Jun 20, 2006
Too much time....

MJP posted:

code:
$users = @(get-aduser -filter * -searchbase "OU=Company Managed Users08,OU=ATL,DC=company,DC=companyname,DC=com" | Ft Surname, Givenname -a | ToArray 
$users += @(get-aduser -filter * -searchbase "OU=Company Managed Users08,OU=BOS,DC=company,DC=companyname,DC=com" | Ft Surname, Givenname -a | ToArray 

Ft is the error you are looking for. Format-Table converts objects to only little more than text strings. Specifically it converts whatever input you give it to another data type, the date type Microsoft.PowerShell.Commands.Internal.Format.FormatEndData! You can only act very superficially with data format-table creates, sort-objects for example can't do anything at all with this data type.

I am not quite sure what the last two pipes of your command are supposed to accomplish. You should be able to create an array of your search results with only:

code:
$users = @(get-aduser -filter * -searchbase "OU=Company Managed Users08,OU=ATL,DC=company,DC=companyname,DC=com")
In a second step you can choose to only display their surname and given name with a select. Please note you are NOT modifying the object. You are simply choosing only to display the specified properties.

code:
$user | select surname, givenname
Finally you can sort your array just like this:

code:
$user | Sort-Object -Property givenname
Are you by any chance coming from a unix shell background? I think like some others you are trying to produce text output instead of using the objects powershell provides.

Edit: I just noticed something. Why are you manually creating an array in the first place?

You can simply write:

code:
$users = get-aduser -filter blah
$users += get-aduser -filter blablah
Whenever powershell needs to assing more than one object to a variable it automatically creates an array. Powershells behavior to automatically flatten arrays might be confusing to some people but check this out:

code:
$arr = get-item ./*
$arr.GetType()

ZeitGeits fucked around with this message at 20:38 on Dec 12, 2012

MJP
Jun 17, 2007

Are you looking at me Senpai?

Grimey Drawer
I'm coming from a background of "We have one client with Office 365, we must use Powershell to perform certain basic distribution list commands, but it looks like I can also do some quick exports from AD with it." Everything I know about PS I'm learning as I go.

Anyway, I need to create an array of multiple OUs - there's upwards of 14, 15ish total. It's meant to list all basic users. If I did $users = blah blah blah for multiple lines and then just typed $users then pressed Enter, the array would only be the last OU. So if I had three get-aduser cmdlets as above, one for ATL, one for BOS, and one for NYC and I did $users = for each of them, I'd only get the NYC users.

I reran my script without changes as my previous post and then manually entered the following commands:

code:
$users | select surname, givenname
$users | sort-object property givenname
I still get this error:
code:
The object of type "Microsoft.PowerShell.Commands.Internal.Format.FormatEntryData" is not valid or not in the correct sequence. This is likely caused by a user-specified "format-*" command which is conflicting with the default 
formatting.
    + CategoryInfo          : InvalidData: (:) [out-lineoutput], InvalidOperationException
    + FullyQualifiedErrorId : ConsoleLineOutputOutOfSequencePacket,Microsoft.PowerShell.Commands.OutLineOutputCommand
I tried your suggestion after I reran the script cleanly again:

code:
$users = get-item ./*
$users.GetType()
Here's the error I get:

code:
The term '.users.GetType' is not recognized as the name of a cmdlet, function, script file, or operable program. Check the spelling of the name, or if a path was included, verify that the path is correct and try again.
At line:1 char:15
+ .users.GetType <<<< (Surname)
    + CategoryInfo          : ObjectNotFound: (.users.GetType:String) [], CommandNotFoundException
    + FullyQualifiedErrorId : CommandNotFoundException
 

ZeitGeits
Jun 20, 2006
Too much time....
Please reread my post. You get the error because of the cmdlet "ft" that you are calling in your script. ft is an alias for format-table. The cmdlet format-table converts you users into a data type that can not be sorted.

Run the following commands exactly as written:

code:
$users = get-aduser -filter * -searchbase "OU=Company Managed Users08,OU=ATL,DC=company,DC=companyname,DC=com"
$users

$users += get-aduser -filter * -searchbase "OU=Company Managed Users08,OU=BOS,DC=company,DC=companyname,DC=com"
$users

$users | sort-object -property givenname
$users | select givenname, username
Do not run your script beforehand. Your script is faulty.

MJP
Jun 17, 2007

Are you looking at me Senpai?

Grimey Drawer
Doing that just dumps a list of users with their individual attributes by DistinguishedName, a long list formatted like this:

code:
DistinguishedName : CN=Doe\, John P.,OU=Company Managed Users08,OU=ATL,DC=company,DC=companyname,DC=com
Enabled           : True
GivenName         : John
Name              : Doe, John P.
ObjectClass       : user
ObjectGUID        : redacted out
SamAccountName    : JPD
SID               : redacted out
Surname           : Doe
UserPrincipalName : [email]JPD@companyname.com[/email]


DistinguishedName : CN=Doe\, Jane Q.,OU=Company Managed Users08,OU=BOS,DC=company,DC=companyname,DC=com
Enabled           : True
GivenName         : Jane
Name              : Doe, Jane Q.
ObjectClass       : user
ObjectGUID        : redacted out
SamAccountName    : JQD
SID               : redacted out
Surname           : Doe
UserPrincipalName : [email]JQD@companyname.com[/email]

givenname : BOS-Test1
username : {}

givenname : Kenneth
username : {}
Problem is I just need the names, so I can then have whoever selects the name pipe the selected name to a cmdlet adding it to a security group at the end of this script.

Mierdaan
Sep 14, 2004

Pillbug

MJP posted:

Doing that just dumps a list of users with their individual attributes by DistinguishedName, a long list formatted like this:

[code]
DistinguishedName : CN=Doe\, John P.,OU=Company Managed Users08,OU=ATL,DC=company,DC=companyname,DC=com
Enabled : True
GivenName : John
Name : Doe, John P.
ObjectClass : user
ObjectGUID : redacted out
SamAccountName : JPD
SID : redacted out
Surname : Doe
UserPrincipalName : JPD@companyname.com

Yes - what you're seeing here are the default display properties for a user object

MJP posted:

Problem is I just need the names, so I can then have whoever selects the name pipe the selected name to a cmdlet adding it to a security group at the end of this script.

No, your problem is that you don't understand how PowerShell works. As soon as you do something like format-table, you're no longer working with the User objects that are returned by the get-aduser cmdlet. This means you're going to have to do a bunch of stupid work to turn strings back into user objects so you can do something with them.

Build your array of user objects, like ZeitGeits told you to. When you have that array of objects, do stuff with the array of user objects. Do not try to convert it to a table of pretty names and then work with that, because at that point you've just lost the user objects.

ZeitGeits
Jun 20, 2006
Too much time....
code:
$users = get-aduser -filter * -searchbase "OU=Company Managed Users08,OU=ATL,DC=company,DC=companyname,DC=com"
creates a collection (array) if the number of returned user objects is > 1. You can choose to only display specific properties of each object in this array with

code:
$users | select-object givenname, surname
The logic is: For each object in the array, output the object, only display the properties givenname, surname specified by select-object.

code:
$users
means: Output the object, display all properties of the object.

You want to work with the object, you do not want to convert it to strings or formatting object with format-table. The reason is this:

code:
$user | ? { $_.surname -eq "foo" } | add-adgroupmember -identity "bar"
This adds every user in $user whose surname is "foo" to the group "bar". Do you see how easy this poo poo is? There is no need to perform complicated string manipulation. Just work with the user object.

MJP
Jun 17, 2007

Are you looking at me Senpai?

Grimey Drawer
But the thing is it's still not sorted alphabetically by surname. Both ZeitGeits and my scripts do successfully list all users from the OUs but neither actually sorts it. The array builds both ways but it's still not sorted, which I'll need before I can even start on the "put the lastname, firstname in a dropdown box" part.

Jelmylicious
Dec 6, 2007
Buy Dr. Quack's miracle juice! Now with patented H-twenty!
Then just sort the list you have:
code:
$users | sort surname | select-object givenname, surname
Or, make your list sorted after you filled it, so it will stay sorted:

code:
$users = $users | sort surname

MJP
Jun 17, 2007

Are you looking at me Senpai?

Grimey Drawer
That did it! Below displays the output of the OUs in the $users array after it's sorted by surname in reference, with the aim of helping for the future should anyone ever need:

code:
$users = @(get-aduser -filter * -searchbase "OU=Company Managed Users08,OU=ATL,DC=company,DC=companyname,DC=com")
$users += @(get-aduser -filter * -searchbase "OU=Company Managed Users08,OU=BOS,DC=company,DC=companyname,DC=com")

$users = $users | sort surname
Now I can start researching how to pipe the Name to a dropdown for selection and running add-adgroupmember with that user's name.

One step closer. Thanks to all who contributed, I don't like making GBS threads up threads with my lack of knowledge but my employers' understanding that I'm not academic with Powershell doesn't change their requirement for me to do it. At least I can learn as I go and do the academics concurrently.

Mierdaan
Sep 14, 2004

Pillbug
This thread's all about learning. Check out the Learn PowerShell in a Month of Lunches book, I hear it's pretty good.

The biggest thing with PowerShell is understanding that commands return objects - not strings like normal Linux shell scripting, which everyone is used to. It's a big shift, but thankfully cmdlets are normally named intuitively (guess what 'get-aduser' does?).

ZeitGeits
Jun 20, 2006
Too much time....

MJP posted:

That did it! Below displays the output of the OUs in the $users array after it's sorted by surname in reference, with the aim of helping for the future should anyone ever need:

code:
$users = @(get-aduser -filter * -searchbase "OU=Company Managed Users08,OU=ATL,DC=company,DC=companyname,DC=com")
$users += @(get-aduser -filter * -searchbase "OU=Company Managed Users08,OU=BOS,DC=company,DC=companyname,DC=com")

$users = $users | sort surname
Now I can start researching how to pipe the Name to a dropdown for selection and running add-adgroupmember with that user's name.

One step closer. Thanks to all who contributed, I don't like making GBS threads up threads with my lack of knowledge but my employers' understanding that I'm not academic with Powershell doesn't change their requirement for me to do it. At least I can learn as I go and do the academics concurrently.

Populating a Dropdown list with items in a collection:

code:
[System.Reflection.Assembly]::Load("System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089")

$Form = New-Object System.Windows.Forms.Form
$Form.Width = 300
$Form.Height = 150
$Form.Text = "Name goes here"

$DropDown = New-Object System.Windows.Forms.ComboBox
$DropDown.Location = new-object System.Drawing.Size(100,10)
$DropDown.Size = new-object System.Drawing.Size(130,30)

# Add your function to create a collection of user objects here
# Change $arr in the next line to the name of your collection

ForEach ($Item in $arr) {
    $DropDown.Items.Add($Item) > 0
}

$Form.Controls.Add($DropDown)

$Form.Add_Shown({$Form.Activate()})

$Form.ShowDialog()
This script might not run because it requires .NET 4.0. Altering the value after "Version" in the first line changes that. Now add a button to the form that queries the selected item in the Dropdown list and calls add-adgroupmember.

ZeitGeits fucked around with this message at 16:22 on Dec 17, 2012

MJP
Jun 17, 2007

Are you looking at me Senpai?

Grimey Drawer
Awesome, thanks - right now it's displaying a dropdown by CN. I'll do some digging on my own to figure out how to set it to call that CN for the add-adgroupmember function. Once it tests and works I'll go about just going by lastname, firstname - might as well make it work before I try to make it pretty.

Thank you thank you thank you!

Titan Coeus
Jul 30, 2007

check out my horn

ZeitGeits posted:

This script might not run because it requires .NET 4.0. Altering the value after "Version" in the first line changes that.

Any reason you can't just do
code:
[System.Reflection.Assembly]::Load("System.Windows.Forms")
to avoid that?

ZeitGeits
Jun 20, 2006
Too much time....

Titan Coeus posted:

Any reason you can't just do
code:
[System.Reflection.Assembly]::Load("System.Windows.Forms")
to avoid that?

Load requires the long form of the library name to load (link). It is possible to use LoadWithPartialName like this:
code:
[System.Reflection.Assembly]::LoadWithPartialName("Systems.Windows.Forms")
but this function is deprecated. You don't want to write a script that is going to fail at some point in the future when Microsoft decides to remove that function.

Edit: A workaround is to use the cmdlet Add-Type,
code:
Add-Type -AssemblyName "System.Windows.Forms"
but Add-Type has exactly the same problems as LoadWithPartialName. It introduces ambiguities in the interpretation of the input: Which version of System.Windows.Forms do you want loaded?

ZeitGeits fucked around with this message at 19:45 on Dec 17, 2012

stubblyhead
Sep 13, 2007

That is treason, Johnny!

Fun Shoe
A question about error handling for you guys. I'm working with the vmWare powerCLI, but the concepts I'm wondering about should be universal. So I have some try-catch blocks kind of like this:

code:
try {
  $datastore = $vmhost | get-datastore | where-object { some conditions } | get-random
}
catch {
  write-error $Error[0]
  Exit 1
}
I was working under the faulty assumption that the line in the try block would throw an error if there were no objects satisfying the condition, but it just sets $datastore to null which makes things blow up later on.

I was planning to just add something like this to the try block:
code:
if ($datastore -eq $Null) {
  throw "no such datastore"
}
Is this my best option, or is there a better way of doing this?

MJP
Jun 17, 2007

Are you looking at me Senpai?

Grimey Drawer
Okay, so I'm trying to add the button and get it to take input from the dropdown. Problem is I can't get a button added.

I've taken my script and just below ZeitGeits' successful dropdown code, added the following:

code:
$OKButton = New-Object System.Windows.Forms.Button
$OKButton.Location = New-Object System.Drawing.Size(75,120)
$OKButton.Size = New-Object System.Drawing.Size(75,23)
$OKButton.Text = "OK"
$OKButton.Add_Click({Return-DropDown})
$objForm.Controls.Add($OKButton)
It gives the following error:

code:
You cannot call a method on a null-valued expression.
At U:\Move Users to Admin.ps1:112 char:22
+ $objForm.Controls.Add <<<< ($OKButton)
    + CategoryInfo          : InvalidOperation: (Add:String) [], RuntimeException
    + FullyQualifiedErrorId : InvokeMethodOnNull
The script still continues running and displays the dropdown list but no buttons on the form. If I remove the offending line of $objForm.Controls.Add($OKButton) then I don't get the error, but still no button.

As to setting a command for the OK button, how would I change this line to say "when the OK button is clicked, run add-adgroupmember -identity AdminUsers -Members %selectionfromdropdownabove%"?

Edit: changed the $OKbutton part to include the return-dropdown alias, which I'm hoping will be usable to take the dropdown selection and pipe to add-adgroupmember later. That alias is as follows:

code:
function Return-DropDown {

	$Choice = $DropDown.SelectedItem.ToString()
	$Form.Close()
	Write-Host $Choice

}

MJP fucked around with this message at 16:20 on Dec 19, 2012

ZeitGeits
Jun 20, 2006
Too much time....
Dude, I don't mean to offend you. But at this point in time you are practically doing cargo cult scripting, copy and pasting code found on the internet in the hope it might work without any deeper understanding what the code actually does. I recommend you buy the book "PowerShell in a month of lunches", it serves as a good entry point to scripting with PowerShell. We might help you to solve your problem this time, but what about the next time your boss assigns you a task requiring you to script in PowerShell?

I will help you one last time in the hope you actually learn something from my examples:
code:
$objForm.Controls.Add($OKButton)
You copy and pasted the block adding the button from some example found on the internet. Of course PowerShell returns the error 'You cannot call a method on a null-valued expression.' You are trying to call the method .Add() on the non-existing object '$objForm'. But the form object you created with my code example is called '$Form'!
code:
$OKButton.Add_Click({Return-Dropdown})
Return-Dropdown is not an alias, it's a function defined earlier in your script. The brackets {} define a script block. If the button is clicked the commands within the script block are executed. In this case the function Return-Dropdown is called.

To get the item selected by the user you have to query the dropdown list object $DropDown. The attribute $Dropdown.SelectedItem returns the selected item; who would have thought?

Knowing this a possible solution is something like this
code:
[System.Reflection.Assembly]::Load("System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089")

function Add-ToGroup($arg) {

# Remove the comment sign if you actually want to test this script
# Add-ADGroupMember $arg NAME_OF_GROUP

Write-Host "You would have added the user $($arg.DistinguishedName) to some group."
}

$Form = New-Object System.Windows.Forms.Form
$Form.Width = 150
$Form.Height = 150
$Form.Text = "Name goes here"
$Form.FormBorderStyle = [System.Windows.Forms.FormBorderStyle]::Fixed3D

$DropDown = New-Object System.Windows.Forms.ComboBox
$DropDown.Location = new-object System.Drawing.Size(5,10)
$DropDown.Size = new-object System.Drawing.Size(130,30)

$users = Get-ADUser -filter * -searchbase "OU=Company Managed Users08,OU=ATL,DC=company,DC=companyname,DC=com"
$users += Get-ADUser -filter * -searchbase "OU=Company Managed Users08,OU=BOS,DC=company,DC=companyname,DC=com"

ForEach ($Item in $users) {
    $DropDown.Items.Add($Item) > 0
}

$Button = New-Object System.Windows.Forms.Button
$Button.Location = New-Object System.Drawing.Size(25,50)
$Button.Size = New-Object System.Drawing.Size(75,23)
$Button.Text = "Add"
$Button.Add_Click({Add-ToGroup($DropDown.SelectedItem)})

$Form.Controls.Add($DropDown)
$Form.Controls.Add($Button)

$Form.Add_Shown({$Form.Activate()})

$Form.ShowDialog()
I have not verified the code because I do not have access to a windows domain in which the PowerShell cmdlets work, but the solution is very, very close to what I wrote. Also the script does not contain any error handling, use at your own risk.

Jelmylicious
Dec 6, 2007
Buy Dr. Quack's miracle juice! Now with patented H-twenty!
An easy place to start, to get a good feel for how powershell starts, is Don's youtube channel: http://www.youtube.com/user/powershelldon
This is from the same author as the month of lunches book. This might help you get a good grip on the quirks that are specific to powershell. If you only watch one video, use this deep-dive (warning, it is 4 hours long) https://www.youtube.com/watch?v=-Ya1dQ1Igkc

adaz
Mar 7, 2009

stubblyhead posted:

A question about error handling for you guys. I'm working with the vmWare powerCLI, but the concepts I'm wondering about should be universal. So I have some try-catch blocks kind of like this:

code:
try {
  $datastore = $vmhost | get-datastore | where-object { some conditions } | get-random
}
catch {
  write-error $Error[0]
  Exit 1
}
I was working under the faulty assumption that the line in the try block would throw an error if there were no objects satisfying the condition, but it just sets $datastore to null which makes things blow up later on.

I was planning to just add something like this to the try block:
code:
if ($datastore -eq $Null) {
  throw "no such datastore"
}
Is this my best option, or is there a better way of doing this?

Define best? We can get into a huge argument about this but in general exceptions should only handle exceptional events. Should your dataStore pretty much always be available and it really would be something catastrophic if it wasn't? If so, then yeah go ahead and throw an exception.

If, on the other hand, the datastore might intermittently be there depending on some factors I would wrap the getting a datastore in a function that returned a value and check the value.

AreWeDrunkYet
Jul 8, 2006

Disregard, I had code inside a comment block and could not figure out why it was not working.

AreWeDrunkYet fucked around with this message at 16:49 on Dec 21, 2012

Erwin
Feb 17, 2006

For baby's first PowerShell script, I'd like to take a folder full of files and zip them up by month (e.g. 2012-10.zip, 2012-11.zip...). This is actually baby's second script, my first was another zipping script, so that part I can handle. The problem is that when I group the files, I can no longer iterate with a foreach. I don't think I understand how groups are interacted with.

Here's the line in question:
code:
$FilesToZip = Get-ChildItem $RemoteDir | Where-Object {snip*} | Group-Object {$_.LastWriteTime.ToString("yyyy-MM")};
This:
code:
ForEach ($Group in $FilesToZip) 
{
	Write-Host $Group;
}
Outputs this:
code:
Microsoft.PowerShell.Commands.GroupInfo
...for each group that exists.

This:
code:
ForEach ($Group in $FilesToZip) 
{
	ForEach ($File in $Group)
	{
		Write-Host $File;
	}
}
...outputs the exact same thing. I can't find any documentation on grouping, to see if I need to use $Group.something. How do I use groups?

*edit: removed inconsequential stuff to fix table breaking.

AreWeDrunkYet
Jul 8, 2006

I'm trying to use the following commands:

code:
$variables = import-csv variables.csv
foreach ($variable in $variables){
$users = get-aduser -filter * -searchbase $variable -properties DisplayName,distinguishedname,description,mail
}
But every time I try to run it, I get

code:
The supplied distinguishedname must belong to one of the following partition(s): (List of OUs)
variables.csv is a list of OUs in the correct format, and I've run

code:
$variables = import-csv variables.csv
foreach ($variable in $variables){
$variable
}
to confirm that it is pulling the correct list of strings. When I try to run the get-aduser command with the searchbase strings entered manually, the command works fine. I'm guessing it has something to do with how those strings are being parsed, but I'm stuck figuring out what exactly. I've tried putting quotes around the searchbase strings in the csv file and casting the searchbase using [string]$variable, neither does anything.

What am I doing wrong?

Adbot
ADBOT LOVES YOU

peak debt
Mar 11, 2001
b& :(
Nap Ghost
import-csv creates rows of columns. If you do a foreach over them, you still get an array of columns for each loop, even if it is a one-member array, and get-aduser expects a string.

You either have to:
$users = get-aduser -filter * -searchbase $variable.ColumnName -properties DisplayName,distinguishedname,description,mail

or use
foreach ($variable in (get-content variables.csv))
to loop over each line as string

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