Editing ADPropertyValueCollection (IList) - powershell

From AD, I obtained a variable with ADPropertyValueCollection type with System.Security.Cryptography.X509Certificates.X509Certificate inside.
Looks like this:
> $test
Handle Issuer Subject
1234 CA1 CN=user1
2345 CA2 CN=user2
3456 CA3 CN=user3
I want to remove one position from the list, and add another one. Unfortunately I have no idea on how to do it - I found that this is an IList, which supports Remove method, but it seems I don't know how to use it.
I thought that maybe PS supports something like
$test[Handle = 1234], but apparently it doesn't.

You invoke IList.Remove() by passing the object that you want removed to it as an argument, so you could do something like:
$objectToRemove = $test |Where-Object Handle -eq 1234 |Select-Object -First 1
$test.Remove($objectToRemove)

Related

Is there a way to put a counter column when doing Get commands in PowerShell?

I need to extract a Get command results into a CSV. The order column should be automatically generated upon a call and give each object its counter upon its appearance in the list. Would this be possible?
For example, when I'd do something like
Get-VMHost | Select #{N="Order";E={$suborder++}}, Name, Version, Build | Export-Csv -path .\smth.csv
I would like to get a result like
Order Name Version Build
----- ---- ------- -----
1 servername1 1.1.1 11111111
2 servername2 1.1.1 11111111
3 servername3 1.1.1 11111111
Would this be possible without using an array?
There are two problems with the current approach:
Unary ++ doesn't output anything by default
Select-Object runs property expressions in their own scope, so you're not actually updating $suborder, you're creating a new local variable every time.
The first problem can be solved by wrapping the operation in the grouping operator (...):
... | Select #{N="Order";E={($suborder++)}}, ...
The second problem can be solved by obtaining a reference to an object that exposes the suborder value as a property.
You can either use a hashtable or a custom object to "host" the counter:
$counter = #{ suborder = 1 }
... | Select #{N="Order";E={($counter['suborder']++)}}
... or you can make PowerShell wrap the original variable in a PSRef-wrapper by using the [ref] keyword:
$suborder = 1
... | Select #{N="Order";E={(([ref]$suborder).Value++)}}

Why is Enumeration Name property not working?

I have a script that i want to display the connection strings of a database
Import-Module SqlServer
$AS = New-Object Microsoft.AnalysisServices.Server
$AS.connect("server1")
Now if i use the FindByName() property
$db = $AS.Databases.FindByName("database1")
$db.DataSources[0].ConnectionString
I get back the connection string successfully
however if i use Enumerator
foreach ($db in $AS.Databases.GetEnumerator())
{ $dbName = $db.Name
$dbName
$dbName.DataSources[0].ConnectionString
}
I get back the database name along with error/exception (because it couldnt get connection string for some reason):
database1
Cannot index into a null array.
database2
Cannot index into a null array.
I tried the following also:
$database1 = "database1"
$database1.DataSources[0].ConnectionString
and i also get back the same exception
So why is it that only FindByName works?
for additional info, this is what GetEnumerator lists:
$AS.Databases.GetEnumerator()
but also $AS.Databases
outputs the same thing...so whats even the point of the enumerator?
gm -i $AS.Databases
gm -i $AS.Databases..GetEnumerator()
Part of what you're seeing is PowerShell's handling of (some) enumerables. Many (most?) are unrolled by PowerShell automatically, so the call to .GetEnumerator() isn't needed.
That's what's happening in your last example, looking at $AS.Databases vs $AS.Databases.GetEnumerator(). But it's only because you sent it out to the pipeline in that case; it's the display process that did the unrolling (in both cases).
If you did gm -i $AS.Databases vs gm -i $AS.Databases.GetEnumerator() you're going to see the difference; same if you assigned each of those to a variable and tried to call methods on them.
But back to using foreach it should again be redundant: foreach ($db in $AS.Databases) should work the same as foreach ($db in $AS.Databases.GetEnumerator()) but I don't have this type in my env right now to test that.
So back to the issue at hand inside the foreach, I suggest you start checking types again. Compare:
$db = $Analysis_Server.Databases.FindByName("database1")
gm -i $db
to
foreach ($db in $AS.Databases.GetEnumerator())
{
gm -i $db
break
}
You might find the types aren't what you think.
This is especially true because you're using dot . notation, because PowerShell has another array shortcut built-in since version 3, whereby you can use . on an array of types, to return an array of the .Property of each item. For example:
$p = Get-Process chrome # choose your own adventure
$p.Count
$p[0].Name
$p.Name
So a property you thought you were accessing on a single object, may have been on an array of objects, and may have been returning an array (or a single object), and handing that in the foreach may have returned a different quantity, or something, resulting in your attempt to index into what used to be an array, no longer work.
But again it's speculation on my part because I don't have those objects. Hopefully this helps you dig deeper into it though.
PowerShell does its own enumerating.
This done the trick!
foreach ($db in $AS.Databases){
Write-Hst $db.Name -Fore green
$db.DataSources | ForEach-Object{$_.ConnectionString}
}

O365 Powershell | Breaking up a long list into two sets of 100

I am looking to create a rule in Office 365 applied to all of the members in our org.
I would like this rule to append a warning on all incoming email from outside the organization with the same Display Names as our users.
When I attempt to apply it to all of the users in our org I get an error stating that the rule is too long.
In order to solve that I pulled a group, but I am still about 1000 characters over the limit.
I would like to make two variables, that each hold one half of the list, created by this command:
(Get-DistibutionGroupMember -Identity email#contoso.com -ResultSize Unlimited).DisplayName
I have attempted to modify the ResultSize parameter, but what I would need is result 1-100 and then 100-200 from the same list.
Another caveat to this problem is that the list cannot be static. It is something that the script will have to update every time it is run.
There is a sub-string command that you can use on a particular username that I have utilized when I made something for AD, but I am not aware of any way to break up a list like this.
If anyone has any other ways to solve this issue I would be more than open to any suggestion.
Thanks for taking the time to read this!
There are many ways of doing it. I found it very readable.
My favorite one is this one:
$ObjectList = 1..1000
$Step = 100
$counter = [pscustomobject] #{ Value = 0 }
$ObjectListSplitted = $ObjectList | Group-Object -Property { math]::Floor($counter.Value++ / $step) }
Then if you want to show the third subset just use this format :
$ObjectListSplitted[3].Group
Have a look to this solution already explained.
As a note other languages are capable of slicing an array of object with a start, stop and a step, have a look here if you're curious.

Powershell - Display value of an object's properties, where the property names are like '*quota*'

As per the subject, I'm trying to get the name of a property and the value assocaited with that property, for a specific mailbox.
So, the line below gets me a nice list of the available object properties, and a default column displayed in the output has the heading 'Name'
Get-Mailbox -Identity "Person Name" | gm
I then want to say something like:
For the object: "Mailbox of Person Name"
Where the property of "Mailbox of Person Name" has a name like 'quota'
List both the actual property name and it's value for "Mailbox of Person Name"
I've tried a number of things using -ExpandProperty/Select-Object/Where-Object but they're all failing. I'm sure this is pretty basic, but Powershell is definitely not my strength. Can anyone show me how to structure this pipeline correctly?
You do not need to use Where-Object, only Select-Object:
Get-Mailbox -Identity "Person Name" | Select-Object -Property *quota*
You seem to have used the correct commandlets. Where-Object filters. Select-Object selects specific properties.
From my experience, sometimes what you see on the console doesn't match the actual property name because there is a formatter that can even change the column name. If you you drive the Where-Object and Select-Object with that virtual property name then they do fail. Also sometimes, the output is not really a recordset that works well with these cmdlets.
My advice is to always check the type of an object when things go strange. Starting from $items=Get-Mailbox -Identity "Person Name".
Then $items.GetType() reveals the actual .net type.
Then $items.Count reveals if it is actually an array or a single object.
Then $items|ForEach-Object {$_.GetType()} reveals the type of each object.
Also the $items|Get-Member is very helpful to figure out the property names. If necessary use it also within your loop.
That is how I troubleshoot strange behaviors and if you can post your findings and the code you tried with Where-Object and Select-Object that would be a great help.

PowerShell Populate multi value attribute and convert case

I've tried to search but could not find anything whcih is not a surprise as I don't think what we're trying to do is so common.
I have a script that gathers a AD users according to filter together with custom attributes properties, we use a custom extended schema, and their values.
I do have an attribute called smtpHistory where an history of SMTP assigned to user are stored, I need to add what's in the $_.email attribute as the primary SMTP address (with SMTP in uppercase) while convertting any existing entry in lower case.
What I am doing right now is similar to
$mailHistory = $_.smtpHistory
$lowerMailHistory = $mailHistory.tolower()
# Insert all existing addresses in lowercase to the history attribute
Set-ADUser $_.SamAccountName -add #{ smtpHistory= $lowerMailHistory }
$newMail = $_.mail
# Append new default email address to smtpHistory
#Set-ADUser $_.SamAccountNAme -Add #{ smtpHistory= "SMTP:$newMail" }
Technically speaking the above works but when I check the smtpHistory attribute what I get is multiple values on a single line like
smtp:test7#gmail.com smtp:test6#gmail.com
Instead of one value per line like
smtp:test7#gmail.com
smtp:test6#gmail.com
The way I'm cycling through the users is via
$usersProxyAddress | ForEach-Object { ...
As using a foreach ($a in $usersProxyAddress ) is yielding the DN of each user and I cannot access the single properties (probably my fault).
Probably this is something silly that I'm overlooking but I cannot find a solution to the issue and any pointer/help would be highly appreciated.
Thanks in advance, Dan.
try something like this
$mailHistory = $_.smtpHistory -join ';'
$mHistory = $mailHistory -spilt ";"
foreach($mH in $mHisotry)
{
#yourcode
}
"Need to be tested as i dont have domain controller available with me now."