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
The Claptain
May 11, 2014

Grimey Drawer
I am trying to update ProxyAddresses attribute on multiple AD users. The idea is, if user has default Proxy Address set (denoted by uppercase SMTP:) add new one as an alias (with lowercase smtp:), and if ProxxyAddresses is not set, or in lowercase, add it in uppercase. This is what I have so far:

code:
Get-ADUser -Filter * -SearchBase 'OU=Test,DC=domain,DC=local' -Properties * |
	ForEach-Object{
		if ($_.ProxyAddresses -cmatch "SMTP")
		{
			Set-ADUser $_ -Add @{ProxyAddresses = "smtp:$($_.UserPrincipalName)"}
		}
		else
		{
			Set-ADUser $_ -Add @{ProxyAddresses = "SMTP:$($_.UserPrincipalName)"}
		}
	}
I doesn't work as expected. If the proxy address is not set, it sets it as expected, matching UPN. If there is a proxy address matching upn, lower or upper case, the attribute remains unmodified. And if there is a proxy address not matching UPN, new one is added in uppercase.

I must be missing something painfully obvious, but I can't find out what.

Adbot
ADBOT LOVES YOU

The Claptain
May 11, 2014

Grimey Drawer

PBS posted:

For starters, try changing to clike instead. I don't really see any glaring issues. My guess is you're using match incorrectly, match uses regex. I've never really taken the time to figure out match, but it is generally faster than like.

code:
Get-ADUser -Filter * -SearchBase 'OU=Test,DC=domain,DC=local' -Properties * |
	ForEach-Object{
		if ($_.ProxyAddresses -clike "*SMTP*")
		{
			Set-ADUser $_ -Add @{ProxyAddresses = "smtp:$($_.UserPrincipalName)"}
		}
		else
		{
			Set-ADUser $_ -Add @{ProxyAddresses = "SMTP:$($_.UserPrincipalName)"}
		}
	}
You could try -cmatch 'SMTP.*' too if you want to stick with match.

Tip, use regexr to test your regex.

Match will return $true if a value is found anywhere in the string. I tested the output of cmatch, and it returns the correct values.

The Claptain
May 11, 2014

Grimey Drawer

Briantist posted:

ProxyAddresses is multi-valued (it's an array). -Add adds an attribute to the AD object, but it won't add a value to a multi-valued attribute. The attributes value itself must be complete, so you will have to create / modify the array itself in code before passing it to Set-ADUser.

I thought I was doing something wrong with regards to multi-valued attribute, and not with the rest of the script.

[/quote]This also means that your check is not quite doing what you think, but it will still work (mostly). When you use the -match or -like (or most) operators with the left side being an array, instead of returning a boolean value it returns an array containing the items that match.

In your case this kind of works, since if there are no entries that match the pattern the result will be an empty array, which will evaluate to false, and an array of any size will evaluate to true. The thing where you have to be careful with that pattern is that it looks for SMTP anywhere in the string it searches.

Consider a proxy address like this: smtp:IheartSMTP@example.com

That will match your pattern. Instead, anchor it at the beginning of the string using ^SMTP:.[/quote]

I was aware of this, but left it aside "I'll whink about it when I get the rest of the script working".

quote:

Once you've done that, you'll have to (re)construct the addresses array before setting it on the object, at which point you need to use the -Replace operator rather than -Add:

code:
Get-ADUser -Filter * -SearchBase 'OU=Test,DC=domain,DC=local' -Properties * |
	ForEach-Object{
                $current = $_.ProxyAddresses
		if ($current -cmatch "^SMTP:")
		{
                        $current += "smtp:$($_.UserPrincipalName)"
			Set-ADUser $_ -Replace @{ProxyAddresses = $current }
		}
		else
		{
                        $current += "SMTP:$($_.UserPrincipalName)"
			Set-ADUser $_ -Replace @{ProxyAddresses = $current}
		}
	}

Unfortunately, this throws out an exception:
code:
Set-ADUser : The specified value already exists
At line:7 char:4
+             Set-ADUser $_ -Replace @{ProxyAddresses = $current }
+             ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : NotSpecified: (CN=1,OU=Test,DC=fried,DC=tv:ADUser) [Set-ADUser], ADException
    + FullyQualifiedErrorId : ActiveDirectoryServer:8323,Microsoft.ActiveDirectory.Management.Commands.SetADUser
I thought that maybe I should use the creplace parameter instead of the replace, but I get "Parameter cannot be found" error.

e: Nevermind, I'm dumb and this works perfectly. I was trying to add the same proxy address. Don't script without morning coffee.

Thanks for the help!

anthonypants posted:

Hey, I did this a while back and posted about it

I should have searched the thread more, so thank you, too.

The Claptain fucked around with this message at 10:03 on Mar 13, 2017

The Claptain
May 11, 2014

Grimey Drawer
Are you running an elevated Powershell? Also you may not have appropriate permissions on objects, even as an administrator on the machine, so you may need to first take ownership and grant yourself appropriate permissions.

The Claptain
May 11, 2014

Grimey Drawer

nielsm posted:

I'm wondering if there are some idioms or syntaxes I'm missing, working with the regular MS ActiveDirectory module.

Say I have a list of user names, and a list of group names. I want to know what users are not in each group, and I want to simply add the missing users. Using Add-ADGroupMember with -Members @("user1", "user2") fails if even a single of the users is already member of the group, and making a loop (ForEach-Object) over the users is awkward and seems backward. Is there a better way?

Is there a good way to present a table (matrix) of AD user objects (with MemberOf property fetched) with some select groups as columns, containing member true/false flags? One that doesn't involve a loop and Add-Member (or creating PSCustomObjects).

I'm phone posting, so I can't check this, but you could probably use Compare-Object cmdlet on outputs of Get-ADUser and Get-ADGroupMember, which should return you a list of users that are not in a specified group.

Something like:
code:
$ADUsers = Get-ADUser...
$GroupMembers = Get-ADGroupMember...
$UsersToAdd = Compare-Object -referenceObject $ADUsers -differenceObject $GroupMembers
You can also use -passThru parameter of Compare-Object to pass the object created to the pipeline if for some reason you do not want it stored in the variable.

The Claptain fucked around with this message at 13:21 on Nov 14, 2017

The Claptain
May 11, 2014

Grimey Drawer
Hello Goons, I have two problems I'd appreciate some input on.

First: I am tracking some stuff related to weekly releases via Azure App Config feature flags. Feature flags are in a format of $environmentName-$releaseVersion, where releaseVersion is a string of format YYYY-WW, so for example this week's one would be 2023-14. I would like to delete the feature flags older than 5 releases.

That format is something that is easy to construct from get-date cmdlet, as the get-date -UFormat %V will give the week number, and (get-date).year will return the, uhh, year. But converting that string to something that can be compared to date-time object escapes me. Looking at the docs for DateTime struct, it is read-only, so I cannot just construct it at will. So how do I go by comparing two strings that represent YYYY-WW format? Comparing weeks is easy enough, but I have no idea how to handle year rollovers on subtraction/addition.

Second: This one is possibly more Azure related than powershell, but here it goes. I have a custom class which needs to represent app service. It has properties name, which is a string, and SKU, which is Microsoft.Azure.Management.WebSites.Models.SkuDescription. I thought it would be easier to use that type, as then I could more easily compare the SKU on my object with what I get from Get-AzAppServicePlan, and boy was I wrong. When I try running the script, I get the Unable to find type Microsoft.Azure.Management.WebSites.Models.SkuDescription. I have "using namespace Microsoft.Azure.Management.WebSites.Models" at the beginning of the script( according to the documentation, that is what the namespace's called, but I tried Microsoft.Azure.Management.WebSites as well, and I am importing Az.Websites module, but the error is still happening. I only get access to the class if I run any command from Az.Websites modules, but since this is supposed to be an Azure runbook, that's not going to work. This one is driving me crazy so much that I decided to:
a) gently caress Azure.Management assemblies and namespaces, It is less effort to write a custom class for SKU
b) gently caress Az powershell modules and their inconsistencies, I should probably rewrite this to use REST API and use an Azure function instead of the runbook

The Claptain
May 11, 2014

Grimey Drawer

Hammerite posted:

you say that you want to keep the last 5, not keep them based on some property of the dates themselves; and they are in YYYY-WW format. so why not just compare the strings? you don't need to turn them into dates to do what you describe. they will compare the correct way lexicographically

I totally forgot you could do that. It works perfectly, and I was way overthinking it.
Thanks!

e: the main reason I was thinking about the dates is because that way it would be easy to subtract five weeks and than do comparisons, but I can work around that.

The Claptain fucked around with this message at 12:10 on Apr 3, 2023

Adbot
ADBOT LOVES YOU

The Claptain
May 11, 2014

Grimey Drawer

vibur posted:

I'm pulling data from a REST API into objects so I have a bunch of Property: Value pairs.

For example:
code:
name                  : iPad
udid                  : a long udid
Mobile Device Group   :
id                    : 663
Display_Name          : iPad
Asset_Tag             : A5035
Last_Inventory_Update : 2023-07-01 22:59:23
Serial_Number         : XXXXXXXXXX
Battery_Level         : 50
I need to push those into a Google Sheet for data viz purposes. Google's API wants JSON but it just wants the values (because each set of values is another row). What I can't figure out is how to get just the values from the object when I don't know the property names ahead of time. I feel like this should be pretty basic object manipulation but I just can't put my finger on it. Anyone know how to do that offhand?

You can use PSObject property (https://learn.microsoft.com/en-us/dotnet/api/system.management.automation.psobject.properties?view=powershellsdk-7.2.0to) get all properties on your object and then you could loop through them

So if you assigned your response to variable $response, you can do something like

code:

Foreach ($property in $response.PSObject.Properties) {
$array+=$property.Value
$array | ConvertTo-Json
I'm typing this half drunk, so it probably needs some fine tuning, but that should give you an array containing only the values.

Edit: if your response is an array of objects, you just wrap the above in another foreach loop, to parse every object separately.

The Claptain fucked around with this message at 01:02 on Jul 8, 2023

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