Select single object from an Object Group - powershell

How do I fix this:
There are 2 objects in this group,
one contains a name under 'Move-In (Name)', one doesn't:
$rest.Group | select * | Where-Object {$_.SERV_UNIT -eq '2704'}
Account_no : 12345
SERV_UNIT : 2704
FINALREAD :
Move-In (Name) : OWNER / CURRENT TENANT
Move-In (Home Phone #) :
Move-In (Business Phone #) :
Move-In (Email) :
Account_no : 12345
SERV_UNIT : 2704
FINALREAD :
CHANNEL_ID :
Move-In (Name) :
Move-In (Home Phone #) :
Move-In (Business Phone #) :
Move-In (Email) :
I want to select only the one with a move in name.
However, with the code I've written, because they're apart of the same group, I will not pick up either:
$rest = $allinfo | Group-Object account_no | Where-Object { $_.Group.FINALREAD -contains '' -and $_.Group.'Move-In (Name)' -notcontains ''} | Select * -Unique
$rest now equals nothing. I want it to have one result, the first one with 'Owner' as the Move-in name.
To get the correct result I have to do this:
$rest = $allinfo | Group-Object account_no | Where-Object { $_.Group.FINALREAD -contains ''} | Select * -Unique
$newRest = #()
foreach ($row in $rest.group) {
if ($row.'Move-In (Name)' -notcontains '')
{
$newRest += $row
}
}
Is it possible to do that all within this one line?
$rest = $allinfo | Group-Object account_no | Where-Object { $_.Group.FINALREAD -contains '' -and $_.Group.'Move-In (Name)' -notcontains ''} | Select * -Unique
If not, it's alright, I have an answer.
Thanks for help

Maybe you can remove the records you don't need (empty Move-In) first, then group by account and list the account-groups that contains one or more blank FINALREAD-values
$rest = $allinfo | Where-Object { $_.Group.'Move-In (Name)' } | Group-Object account_no | Where-Object { $_.Group.FINALREAD -contains '' }

Related

How to merge 2 properties into single output of AD Objects?

I need to merge two properties into one column, name of user is in DisplayName while Name of group is stored in Name how ever both types of objects has DisplayName, Name properties so I need to show them in one column.
Suppose Group is 'Test Group'
CN : …
ObjectGUID : 123-456-XXXX
ObjectClass: group
DisplayName:
Name: 'Test Group'
And 'Test User' Properties are
CN: …
ObjectGUID : 789-456-XXXX
ObjectClass: user
DisplayName: 'Test User'
Name:
I have tried using a for each looping but can't figure out the use of select statement.
Get-ADGroupMember -Identity $GroupGUID |
ForEach-Object{
if($_.ObjectClass -eq 'User'){
# process user object
$_ | Get-ADUser -Properties DisplayName
}elseif ($_.ObjectClass -eq 'User'){
# process group
$_ | Get-ADGroup -Properties Name
}
}
The expected output need to be
MemberName ObjectGUID
---------------- ------------------
Test Group 123-456-XXXX
Test User 789-456-XXXX
I'd use a switch statement to process each item depending on if it is a user or group, and then replace the MemberName property depending on what it is:
$Results = Switch(Get-ADGroupMember -Identity $GroupGUID){
{$_.ObjectClass -eq 'User'} {$_ | Get-ADUser -Prop DisplayName | Select *,#{l='MemberName';e={$_.DisplayName}} -ExcludeProperty MemberName}
{$_.ObjectClass -eq 'Group'} {$_ | Get-ADGroup | Select *,#{l='MemberName';e={$_.Name}} -ExcludeProperty MemberName}
}
$Results|Select MemberName,ObjectGUID
Or if you really want it all done in the pipeline you could do this:
Get-ADGroupMember -Identity $GroupGUID -PipelineVariable 'Member' | ForEach{If($Member.ObjectClass -eq 'User'){$_ | Get-ADUser -Properties DisplayName}Else{$_ | Get-ADGroup}} | Select #{l='MemberName';e={If($Member.ObjectClass -eq 'User'){$_.DisplayName}Else{$_.Name}}},ObjectGUID
i think you are wanting to merge the sources into one output object.
the usual way to add values from multiple sources into one object is to use a [PSCustomObject] to build a ... custom object. [grin] i don't have any AD access, so this is done with local user & group info. you can do some fairly complex structuring by calculating what you want to work with and stuffing it all into one neatly structured object.
here's a demo of the idea using local accounts ...
$GroupName = 'Homonymic_Tuu'
$MemberList = Get-LocalGroupMember -Group $GroupName |
Where-Object {$_.ObjectClass -eq 'User'}
$GroupInfo = Get-LocalGroup -Name $GroupName
foreach ($ML_Item in $MemberList)
{
$UserInfo = Get-LocalUser -Name $ML_Item.Name.Split('\')[-1]
if ([string]::IsNullOrEmpty($UserInfo.LastLogon))
{
$LastLogon = '_Never_'
}
else
{
$LastLogon = $UserInfo.LastLogon
}
[PSCustomObject]#{
Group_Name = $GroupInfo.Name
Group_Description = $GroupInfo.Description
User_Name = $UserInfo.Name
User_Description = $UserInfo.Description
User_Enabled = $UserInfo.Enabled
User_LastLogon = $LastLogon
}
}
truncated output ...
Group_Name : Homonymic_Tuu
Group_Description : Homonym - sounds like Tuu
User_Name : 22
User_Description : The Digit 2 Twice
User_Enabled : True
User_LastLogon : 2018-11-27 9:19:10 PM
[*...snip...*]
Group_Name : Homonymic_Tuu
Group_Description : Homonym - sounds like Tuu
User_Name : TwoTwo
User_Description : Repeating the name of the number after One.
User_Enabled : True
User_LastLogon : _Never_
the data will also export to a CSV file quite easily. [grin]

Check if Two Values in Array / Data Table match

I put this question on here before, but I missed an important detail which causes huge issue. There will be duplicate account numbers. So I'm doing it by current_read_date now to avoid duplicates in account number. To ensure values being added to $accounts are new from the CSV.
I am trying to get all the accounts from $f which do not match the accounts in $table4 into $accounts. But I need to also check if the current_read_date matches or not.
CSV into Array $f:
Account_no |occupant_code|current_read_date
-----------|-------------|-----------------
12345 | 1 | 7/17/2017 15:32:00 AM
67890 | 2 | 7/17/2017 12:00:00 AM
45678 | 3 | 7/17/2017 12:00:00 AM
DataTable $table4
Account_no |occupant_code|current_read_date
-----------|-------------|-----------------
12345 | 1 | 7/17/2017 12:00:00 AM
12345 | 1 | 7/17/2017 15:32:00 AM
67890 | 1 | 7/17/2017 13:00:00 AM
67890 | 1 | 7/17/2017 22:00:00 AM
45678 | 3 | 7/17/2017 12:00:00 AM
Desired result:
$accounts =
67890 | 2 | 7/17/2017 12:00:00 AM
Current code:
$accounts = Import-Csv $f |
select account_no, current_read_date |
where { $table4.account_no -notcontains $_.account_no }
What this needs to do is to check that current_read_date doesn't match, i.e.:
12345: account and date from $f and $table4 match; so it's ignored
67890: account matches $table4, but the current_read_date does not match, so it is a new value, thus it is added to $accounts.
I believe I need to use Group-Object, but I do not know how to use that correctly.
I tried:
Import-Csv $f |
select account_no, occupant_code |
Group-Object account_no |
Where-Object { $_.Group.current_read_date -notcontains $table4.current_read_date }
This is the previous question:
How to use Group-Object on this?
All the answers here failed because I forgot to provide the information that account_no is not unique; there will be frequent duplicates.
All assistance would be greatly appreciated, I've been stuck on this for awhile.
I've also tried this
$testList = #()
$testList = Import-Csv $f | select account_no, occupant_code, current_read_date, current_reading
$accounts = new-object System.Collections.ArrayList
$testSet = $table4
foreach($myThing in $testList)
{
if($myThing.account_no -in $testSet.account_no )
{
foreach($ts in $testSet)
{
if ($myThing.account_no -match $ts.account_no -and $myThing.occupant_code -match $ts.occupant_code)
{
$ts.account_no
$ts.occupant_code
}
else {
$accounts.add($myThing) | out-null
write-host $mything
}
}
}
This fails because it goes through each number, therefore, 12345 will be checked against 67890, and will added 12345 to the $accounts list, even though it already exists, because I cannot compare each individually at a time with table4.
Thanks
$accounts = $f | Where {
$Record = $_
$AccNo = $table4 | Where {$_.Account_no -eq $Record.Account_no}
!($AccNo | Where {$_.current_read_date -eq $Record.current_read_date})
}
$accounts | Format-Table
Result:
Account_no occupant_code current_read_date
---------- ------------- -----------------
67890 2 7/17/2017 12:00:00 AM
Build a reference list from the records in $table4
$ref = $table4 | ForEach-Object {
$_.Account_no, $_.occupant_code, $_.current_read_date -join ','
}
then filter the records from $f by that reference list:
$accounts = Import-Csv $f | Where-Object {
$ref -notcontains ($_.Account_no, $_.occupant_code, $_.current_read_date -join ',')
} | Select-Object -Expand Account_no -Unique

Search and export list of available names in AD

I have AD with a lot of computers in it. computer names are made like this: XXXXNNNN (where X=constant part and N=numeric dynamic part of the name). Any thoughts how can I scan names from N=0 --> N=Nmax, and export all unused (free) names to *.txt?
[int]$NMax = (Get-ADComputer -Filter {name -like "XXXX*"} | Sort-Object name | select -ExpandProperty name -Last 1).SubString(4, 4)
$i = 0001
while ($i -ne ($NMax+1))
{
try
{
Get-ADComputer ("XXXX"+$($i.ToString("D4"))) | select name | out-null
}
catch
{
write "No ADComputer with the name: XXXX$($i.ToString("D4"))"
}
$i++
}

Is there a wild card that can be used for any column?

If I already have a variable $test with a set of users.
Each user entry has 10 columns that represent email addresses.
How to return only values with a specific entries from the $test variable.
Example of a user entry:
Alias : User01
EmailAddresses_1 : X500:/o=bla bla bla b
EmailAddresses_2 : x500:/o=bla1 bla1 bla1 bla1
EmailAddresses_3 : smtp:USR1#testdomain1.com
EmailAddresses_4 : smtp:user01#testdomain1.com
EmailAddresses_5 : smtp:user1#testdomain2.com
EmailAddresses_6 : SMTP:user001#testdomain1.com
EmailAddresses_7 : SIP:usr01#testdomain1.com
EmailAddresses_8 : smtp:u1#testdomain2.com
EmailAddresses_9 :
EmailAddresses_10 :
So as you can see, some columns are populated with different values and other are empty.
How can I return only the columns with a specific value assuming I only have the variable to work with.
For example all the user entries with only the values that start with "SIP:*"
A little guiding light is appreciated.
If you are looking for the Alias of all the users that have a property name that starts with EmailAddresses and contains a specific value, this might help you out:
$Test = [PSCustomObject]#{
Alias = 'User01'
EmailAddresses_1 = 'X500:/o=bla bla bla b'
EmailAddresses_2 = 'x500:/o=bla1 bla1 bla1 bla1'
EmailAddresses_3 = 'smtp:USR1#testdomain1.com'
EmailAddresses_4 = 'smtp:user01#testdomain1.com'
EmailAddresses_5 = 'smtp:user1#testdomain2.com'
EmailAddresses_6 = 'SMTP:user001#testdomain1.com'
EmailAddresses_7 = 'SIP:usr01#testdomain1.com'
EmailAddresses_8 = 'smtp:u1#testdomain2.com'
EmailAddresses_9 = $null
EmailAddresses_10 = $null
}
$SearchString = 'SIP:'
$Found = Foreach ($T in $Test) {
$Properties = $Test | Get-Member | Where {($_.MemberType -EQ 'NoteProperty') -and ($_.Name -like 'EmailAddresses*')}
Foreach ($P in $Properties) {
if ($T.($P.Name) -like "$SearchString*") {
$T.Alias
}
}
}
$Found | Select -Unique
After clarification in the comments, this might be more what you're looking for:
$SearchString = 'SIP:'
$Test | Select Alias,
#{Name='EmailAddres1';Expression={if ($_.EmailAddresses_1 -like "$SearchString*"){$_.EmailAddresses_1}}},
#{Name='EmailAddres2';Expression={if ($_.EmailAddresses_2 -like "$SearchString*"){$_.EmailAddresses_2}}},
#{Name='EmailAddres3';Expression={if ($_.EmailAddresses_3 -like "$SearchString*"){$_.EmailAddresses_3}}},
#{Name='EmailAddres4';Expression={if ($_.EmailAddresses_4 -like "$SearchString*"){$_.EmailAddresses_4}}},
#{Name='EmailAddres5';Expression={if ($_.EmailAddresses_5 -like "$SearchString*"){$_.EmailAddresses_5}}},
#{Name='EmailAddres6';Expression={if ($_.EmailAddresses_6 -like "$SearchString*"){$_.EmailAddresses_6}}},
#{Name='EmailAddres7';Expression={if ($_.EmailAddresses_7 -like "$SearchString*"){$_.EmailAddresses_7}}},
#{Name='EmailAddres8';Expression={if ($_.EmailAddresses_8 -like "$SearchString*"){$_.EmailAddresses_8}}},
#{Name='EmailAddres9';Expression={if ($_.EmailAddresses_9 -like "$SearchString*"){$_.EmailAddresses_9}}},
#{Name='EmailAddres10';Expression={if ($_.EmailAddresses_10 -like "$SearchString*"){$_.EmailAddresses_10}}}

Powershell: Merge multiple lines into one

I have a .csv file which looks like:
employeenumber;phone;mobile;fax;userid;Email
99999991;+1324569991;+234569991;+5234569991;user01;user1#domain.com
99999992;+1234569992;+234569992;;user02;user2#domain.com
99999993;+1234569993;+234569993;;user03;user3#domain.com
99999993;+12345699933;;;user03;user3#domain.com
99999993;;;+5234569993;user03;user3#domain.com
99999994;+1234569994;;;user04;user4#domain.com
As you can see there are different employeenumbers and some lines with the same employeenumber.
Is there any way to merge the lines with the same employeenumber in powershell?
Similar Output:
employeenumber;phone;mobile;fax;userid;Email
99999991;+1324569991;+234569991;+5234569991;user01;user1#domain.com
99999992;+1234569992;+234569992;;user2;user2#domain.com
99999993;+1234569993 / +12345699933;+234569993;+5234569993;user03;user3#domain.com
99999994;+1234569994;;;user04;user4#domain.com
Thank you
I've taken a shot at it. I believe my answer is easier to read than Mjolinor's.
I group the entries from the CSV into either $singletons or $duplicates, based on using the Group-Object command. Then, I pipe through the $duplicates and merge the records found in either the phone,mobile, or fax fields, using a '/' character as you've indicated.
#$csv = get-content .\CSVNeedstoMerge.csv
$csvValues = $csv | ConvertFrom-Csv -Delimiter ';'
$duplicates = $csvValues | group-object EmployeeNumber | ? Count -gt 1
$objs = New-Object System.Collections.ArrayList
$singletons = $csvValues | group-object EmployeeNumber | ? Count -eq 1 | % {$objs.Add($_.Group)}
ForEach ($duplicate in $duplicates){
$objs.Add([pscustomobject]#{employeenumber=($duplicate.Group.employeenumber | select -Unique) -as [int];
phone=($duplicate.Group.phone | ? Length -gt 0) -join '/';
mobile=($duplicate.Group.mobile| ? Length -gt 0) -join '/';
fax=($duplicate.Group.fax | ? Length -gt 0) -join '/';
userid = $duplicate.Group.userid | select -Unique
email= $duplicate.Group.email | select -Unique })
}
$objs | Sort EmployeeNumber
I'll give that a shot:
(#'
employeenumber;phone;mobile;fax;userid;Email
99999991;+1324569991;+234569991;+5234569991;user01;user1#domain.com
99999992;+1234569992;+234569992;;user02;user2#domain.com
99999993;+1234569993;+234569993;;user03;user3#domain.com
99999993;+12345699933;;;user03;user3#domain.com
99999993;;;+5234569993;user03;user3#domain.com
99999994;+1234569994;;;user04;user4#domain.com
'#).split("`n") |
foreach {$_.trim()} | sc test.csv
$ht = #{}
$props = (Get-Content test.csv -TotalCount 1).split(';')
import-csv test.csv -Delimiter ';' |
foreach {
if ( $ht.ContainsKey($_.employeenumber) )
{
foreach ($prop in $props )
{
if ($_.$prop )
{$ht[$_.employeenumber].$prop = $_.$prop }
}
}
else { $ht[$_.employeenumber] = $_ }
}
$ht.values | sort employeenumber
employeenumber : 99999991
phone : +1324569991
mobile : +234569991
fax : +5234569991
userid : user01
Email : user1#domain.com
employeenumber : 99999992
phone : +1234569992
mobile : +234569992
fax :
userid : user02
Email : user2#domain.com
employeenumber : 99999993
phone : +12345699933
mobile : +234569993
fax : +5234569993
userid : user03
Email : user3#domain.com
employeenumber : 99999994
phone : +1234569994
mobile :
fax :
userid : user04
Email : user4#domain.com