How to check multiple values in variable against multiple values in hash table or pscustomobject? - powershell

I would like to know how I can check multiple values against multiple values contained in a hash table or pscustomobject?
Just for context, the cmdlets used are for SharePoint.
Here`s my code so far:
$usersSearched = [pscustomobject]#{
DisplayName = (#("Administrator";"Service Administrator";"Company
Administrator"))
LoginName = (#("s-1-5-21-2098222698-275879357-2441446288-39577944";"s-1-5-
21-2098222698-275179357-2441446288-39696162";"s-1-5-21-2098262698-275879357-
2441446288-14998143"))
}
#Returns object with one or more values and has a .LoginName property
$result = Get-SPOUser -Site $site | Where-Object {$_.IsSiteAdmin -eq $True}
If ($usersSearched.LoginName -in $result.LoginName)
#Whatever
{
My propblem is that I am unable to get the condition to return true.
If there`re easier ways to execute this seemingly simple task, please let me know.

First, have to separate entries within an array using a comma, not a semicolon:
$usersSearched = [PsCustomObject]#{
DisplayName = #("Administrator","Service Administrator","Company Administrator")
LoginName = #("s-1-5-21-2098222698-275879357-2441446288-39577944",
"s-1-5-21-2098222698-275179357-2441446288-39696162",
"s-1-5-21-2098262698-275879357-2441446288-14998143")
}
Second, you have to use -contains instead of -in (or you swap the values):
If ($usersSearched.LoginName -contains $result.LoginName)

Related

PowerShell Create a series in System.Object (PSCustomObject)

Is there an easier way to accomplish this without typing the series out? I tried some ideas with arrays and dereferencing, but nothing ended up working.
$rowP = "" | Select-Object Course,"5","6","7","8","9","10","11","12","13","14","15","16","17","18","19","20","21","22","23","24","25","26","27","28","29","30","31","32","33","34","35"
I prefer the following approach.
Create an ordered dictionary:
$properties = [ordered]#{
Course = $null
}
Use the .. range operator to generate the range of integers 5 through 35, add empty entries to the dictionary:
5..35 |ForEach-Object {
$properties["${_}"] = $null
}
Convert the dictionary to a PSCustomObject:
$object = [pscustomobject]$properties
Alternatively, you could also use the range operator to generate the integer range and pass those as property names to Select-Object:
"" |Select-Object -Property #('Course'; 5..35 -as [string[]])

PowerShell Compare AD Groups but show only these what I need

I have a PowerShell script that is generating from a file.txt a list of users and groups where they belong to.
The next step that I need to achieve is to confirm if the group from file Groups.txt is assigned to users.
To do this I used logical operator -contains so the code is looking like that:
$UserList = Get-Content ("C:\users.txt")
$GroupList = Get-Content ("C:\Groups.txt")
$result = #()
foreach ($UserList in $UserList){
$data = New-Object PSObject
$Group = (Get-ADPrincipalGroupMembership -Identity $UserList | foreach {$_.SamAccountName}) -contains $GroupList
$data = get-aduser $Userlist -properties samaccountname,givenname,surname | select samaccountname,givenname,surname, #{name="Groups";expression={$Group}}
$result += $data
}
$result
The code is working when I have only one group in file Groups.txt. If I have two or more it is applying only the last one with value True
The resolution what I expecting is
When the user has one or multiple groups from the file Group.txt script should mention that group name and nothing else.
To be more precise I need something like that as results:
samaccountname givenname surname Groups
-------------- --------- ------- ------
User FirstName Surname False (or anything)
User1 Firstname Surname Group1, Group2, Group3
Many thanks for any help in this matter.
You can do the following:
$UserList = Get-Content "C:\users.txt"
$GroupList = Get-Content "C:\Groups.txt"
$result = foreach ($User in $UserList) {
$Groups = Get-ADPrincipalGroupMembership -Identity $User |
Where SamAccountName -in $GroupList
Get-ADUser -Identity $User -Properties GivenName,Surname |
Select-Object SamAccountName,GivenName,Surname,#{name="Groups";expression={$Groups.SamAccountName}}
}
$result
When using a foreach loop, the proper syntax is foreach ($<item> in $<collection>) { statements }. $<item> is just a variable that you can reference within the statements, and it should be a variable that has not been assigned up until that point. See About_Foreach.
If your foreach statements produce output as in this case, they can simply be collected by assigning a variable to the foreach loop. This will result in a more efficient array assignment. Using += to effectively expand an array, just results in creating a new array on each loop iteration that is bigger than the previous. It is not efficient and is unnecessary in cases like these.
Regarding collection comparison, -contains is used when comparing a left-hand side (LHS) single item with a right-hand side (RHS) collection. A sample syntax would be $<collection> -contains $<single_item>. -in is used when comparing a LHS single item with a RHS collection. A sample syntax would be $<single_item> -in $<collection>. See About Comparison Operators.
Since you ultimately wanted to gather groups from a command output based on a certain condition, that is a prime candidate for Where or Where-Object. It's pseudo code usage is out of these 20 items, show me the ones that meet a certain condition. See Where-Object.

In Powershell, is there a better way to store/find data in an n-dimensional array than a custom object

I find myself continually faced with the need to store mixed-type data in some kind of a structure for later lookup.
For a recent example, I am performing data migration and I will store the old UUID, new UUID, source environment, target environment, and schema for an unknown number of entries.
I have been meeting this need by creating an array and inserting System.Objects with NoteProperty members for each of the columns of data.
This strikes me as a very clumsy approach but I feel like I may be limited by Powershell's functionality. If I need to, for example, locate all entries that used a particular schema, I write a foreach loop that sticks each entry with a matching schema name in a whole new array that I can return. I would really like the ability to more easily search for all objects that contain a member matching a particular value, modify existing members, etc.
Is there a better built-in data structure that will suit my needs, or is creating a custom object the right thing to do?
For reference, I'm doing something like this to create my structure:
$objectArray= #();
foreach(thing to process){
$tempObj = New-Object System.Object;
$tempObj | Add-Member -MemberType NoteProperty -Name "membername" -Value xxxxx
....repeat for each member...
$objectArray += $tempObj
}
If I need to find something in it, I then have to:
$matchingObjs = #()
foreach ($obj in $objectArray){
if($obj.thing -eq value){$matchingObjs += $obj}
}
This really sucks and I know there has to be a more elegant way. I'm still fairly new to powershell so I don't know what utilities it has to help me. I'm using v5.
With PowerShell 3.0 you could use a [PSCustomObject], here's an article on the different object creation methods.
Also setting the array equal to the output of the foreach loop will be more efficient than repeatedly recreating an array with +=.
$objectArray = foreach ($item in $collection) {
[pscustomobject]#{
"membername" = "xxxxx"
}
}
The Where-Object cmdlet or the .where() method looks like what you need in your second loop.
$matchingObjs = $objectArray | Where-Object {$_.thing -eq "value"}
It also sounds like you could use Where-Object/.where() to filter the initial data and just create an object which matches what you are looking for. For example:
$matchingObjs = $InputData |
Where-Object {$_.thing -eq "value"} |
ForEach-Object {
[pscustomobject]#{
"membername" = xxxxx
}
}
If your data can be expressed as key value pairs, then a hashtable will be the most efficient, see about_Hash_Tables for more info.
There is no built-in way to do what you are asking. One way is to segment your data into separate hashtables so you can do easy lookups by a common key, say the ID.
# Create a hastable for the IDs
$ids = #{};
foreach(thing to process){
$ids.Add($uid, 'Value')
}
# Find the $uid exists
$keyExists = $ids.Keys -Contains $uid
# Find value of stored for $uid
$keyValue = $ids[$uid]
As a side note, you don't have to create Syste.Object, you can simple do this:
$objectArray = #();
gci | % {
$objectArray += #{
'Key1' = 'Value 1'
'Key2' = 'Value 2'
}
}
If you need to compare complex objects, you can build them with #{} and then use Compare-Object on the two objects, just another idea.
For example, this will get a file listing of two different directories, and tell me what file exists or doesn't exist between the two directories:
$packages = (gci $boxStarterRepo -Recurse *.nuspec | Select-Object -ExpandProperty Name) -replace '.nuspec', ''
$packages += (gci $boxStarterPrivateRepo -Recurse *.nuspec | Select-Object -ExpandProperty Name) -replace '.nuspec', ''
$packages = $packages | Sort-Object
Compare-Object $packages $done

How to iterate over the properties of an object

I am trying to write a PowerShell script that iterates through the objects properties and outputs only the ones that have a value of True.
My starting data is this:
UserId : 00546000000m3vCAAQ
UserPermissionsOfflineUser : True
UserPermissionsMobileUser : False
UserPermissionsSupportUser : True
UserPermissionsWebUser : False
I would like the output to consist of the UserID and only the licenses that are true like the following:
UserId : 00546000000m3vCAAQ
UserPermissionsOfflineUser : True
UserPermissionsSupportUser : True
I think I need two loops, one to iterate over each user and then another loop to iterate over the user's properties and just parse out all the false values.
foreach ($_ in $resultset)
{
$_ |
Select-Object -Property #{ N = 'UserId'; E = { $_.Id } }
#This is where I am getting stuck on the second loop.
#$_.psobject.properties | % { $_.Value }
}
Use Where-Object to find the properties with a value of $true, then use Select-Object to select those along with the UserID property:
$resultSet |ForEach-Object {
$trueProperties = $_.psobject.Properties |Where-Object {$_.Value -eq $true} |Select -ExpandProperty Name
$_ |Select -Property #('Id';$trueProperties)
}
Be aware that selectively picking out properties based on their value like this may cause you pain later on with Export-* or Format-* cmdlets
The |Select-Object -ExpandProperty Name part grabs the values of the Name property of the properties that made it through our Where-Object filter, so at this point $trueProperties contain 2 strings: "UserPermissionsOfflineUser" and "UserPermissionsSupportUser".
The expression #('Id';$trueProperties) simply concatenates the strings to the "Id" string, so the last Select-Object statement is basically the same as saying:
$_ |Select Id,UserPermissionsOfflineUser,UserPermissionsSupportUser

Issue with Powershell custom table

I'm trying to create a custom table based on two other tables (csv-imported) - some kind of a VLOOKUP, but I can't seem to find a solution. I've come up with the following (failing) code:
$DrawPlaces | select Module, Workplace, #{ Name = "IPaddress"; Expression = {$Workstations.workstation.where($_.WorkPlace -eq $Workstations.Workplace)}} -First 15
Both Drawplaces and $Workplaces are PSCustomObject. The result of this would then go to another variable.
I'm not even sure the logic or syntax is correct, but the result table has the IPaddress column empty. I've also tried with -match instead of -eq.
This doesn't make sense: $Workstations.workstation.where($_.WorkPlace -eq $Workstations.Workplace)
.where() requires a scriptblock parameter like .where({}).
Keeping in mind that inside the where-statement $_ is refering to the current object in the $workstations.workstation-loop, your where-statement is testing ex. $workstations.workstation[0].workplace -eq $workstations.workplace. Is that really what you want?
Are you trying to achieve this?
$DrawPlaces |
Select-Object -First 15 -Property #(
"Module",
"Workplace",
#{ Name = "IPaddress"; Expression = {
#Save the Workspace-value for the current object from $DrawPlaces
$wp = $_.WorkPlace;
#Find the workstation with the same workplace as $wp
$Workstations | Where-Object { $_.WorkPlace -eq $wp} | ForEach-Object { $_.Workstation }
}
}
)