Compare two lists, without Compare-Object - powershell

I have two lists saved in variables $list1 and $list2.
Now I want to compare them. Somehow, Compare-Object is giving me the wrong output, even though the user is in both lists it still says
not equal

Related

Compare Registry properties; hash compare or simple equality

I am looking to do a hash compare of a variety of things; files, folders, registry properties and registry keys.
File hash is easy...
$Hash1 = [System.BitConverter]::ToString($md5.ComputeHash([System.IO.File]::ReadAllBytes($filePath1)))
$Hash2 = [System.BitConverter]::ToString($md5.ComputeHash([System.IO.File]::ReadAllBytes($filePath2)))
if ($Hash1 -eq $Hash2) {}
And folder is easy because I can do a get Get-ChildItem, and if the resulting list isn't identical then the compare is false, and if the list is identical then if any individual file hash isn't identical then the compare is false.
However, I am trying to add registry stuff to this, and I am not clear on how to do the ReadAllBytes() on a registry property. Or, am I really over thinking this since a property is not a complex file, and I should just first check for property kind with $sourceKey.GetValueKind($name) and then compare actual values if the kinds match? Does -eq work with every possible data type in the registry? Or are there gotchas I need to worry about?

Powershell how to subtract a variable from another variable, both contain the Exchange Mailbox Object Identity

I have two variables both which contain the Get-Mailbox object "Identity" of user accounts. I need to subtract the contents of one from the other IE:
$termednofwd = (domain.local/OUname/SubOU/Users/first1 last1, domain.local/OUname/SubOU/first2 last2)
$termedfmr = (domain.local/OUname/SubOU/Users/first1 last1)
I want something that would subtract the contents of $termedfmr from $termednofwd giving something like the below. Compare-Object only lists the contents that are in both, I basically need to subtract what is in both from the first variable.
essentially:
$termednofwdnofmr = $termednofwd - $termedfmr resulting in this:
$termednofwdnofmr = (domain.local/OUname/SubOU/first2 last2)
In set theory terms, you're looking for the relative complement between two collections, which Compare-Object can provide, although it requires additional effort:
By default, Compare-Object provides the symmetric difference between two sets, i.e. it lists the union of relative complements; that is, given two sets A and B, it lists both those elements of B not present in A and those elements of A not present in B, and it uses the .SideIndicator property to indicate which is which:
'<=' indicates objects unique to set A (-ReferenceObject argument, or first positional argument), whereas
'=>' indicates elements unique to set B (-DifferenceObject argument, or second positional argument).
Therefore, you need to filter the output objects by their .SideIndicator values.
The -PassThru switch additionally ensures that the input objects are passed through (as opposed to wrapping them in a [pscustomobject] instance whose .InputObject contains them):
$termednofwd = 'domain.local/OUname/SubOU/Users/first1 last1',
'domain.local/OUname/SubOU/first2 last2'
$termedfmr = 'domain.local/OUname/SubOU/Users/first1 last1'
# Return the elements in $termednofwd that aren't also present in $termedfmr
Compare-Object $termednofwd $termedfmr -PassThru |
Where-Object SideIndicator -eq '<='
The above yields 'domain.local/OUname/SubOU/first2 last2', i.e. those element(s) in $termednofwd that aren't also present in $termedfmr.
Note: The above uses strings as input objects for brevity; in your case, since you're working with the objects returned by the Get-Mailbox cmdlet and want to compare based on their .Identity property values, you need to use:
# If you only need the identity values as results.
Compare-Object $termednofwd.Identity $termedfmr.Identity -PassThru |
Where-Object SideIndicator -eq '<='
# Alternatively, if you need the whole mailbox objects.
Compare-Object -Property Identity $termednofwd $termedfmr -PassThru |
Where-Object SideIndicator -eq '<='
See also: GitHub issue #4316, which proposes enhancing Compare-Object with set operations.
So this is essentially a practical example of Set theory i.e. I'd like all the items from Set 1 that isn't in Set 2. PowerShell doesn't have direct commandlets to do that but through the power of .Net you can lervage the Microsoft Linq libraries to do this work for you.
The only trick is that you need to cast your PowerShell variables to arrays of Objects to make the function call work right:
$results = [System.Linq.Enumerable]::Except([object[]]$mainArray, [object[]]$subArray)
Lastly, the items you are comparing in the two arrays have to be comparable. For simple things like strings this is always works. If the things you are comparing are more complex objects, they may not be comparable directly.

Powershell claims object is null but I can see values

I am trying to compare two objects and I can see both objects have values (and they are the same), but running the compare results in error referenceobject is null. See screenshot
Not sure where to go with this.
I would make a quick check to see if any value is equal to null and then do a comparison if values are found. Even if you can see both objects have values, your ps command may not.
The following accepts null values:
Compare-Object -ReferenceObject #($Value1 | Select-Object) -DifferenceObject #($Value2 | Select-Object)

powershell import-csv two times

This is possibly a silly question but i tried to import 2 csv-files with powershell.
but when i try to write to the screen only the first one shows.
$connectivityCsvFile = #(Import-Csv "C:\connectivity.csv")
$logfileCsvFile = #(Import-Csv "C:\1-log.csv")
$logfileCsvFile
$connectivityCsvFile
print-screen of output
if I change the $logfileCsvFile with $connectivityCsvFile then the connectivity-file is printed and not the logfile
anyone knows why?
I think what PowerShell is doing is selecting the properties to show you based on the types in the first collection you are writing to output. The second collection has objects with entirely different properties and so the values default to blanks.
The lines
$logFileCsvFile
$connectivityCsvFile
don't really show you the values (at least that's not their primary effect). They cause the script to write the values to the output stream. The values in this stream are then displayed at the end of the command. Having an output stream with two different kinds of objects kind of messes up the default display behavior.
If you want to output to be print in a table format, you should use Format-Table (ft):
$logfileCsvFile | ft
$connectivityCsvFile | ft

Getting most recent objects in a folder excluding certain strings

I have folders that contain files, for the sake of the question, named as follows:
a-001.txt
a-002.txt
b-001.txt
b-002.txt
d-001.txt
d-002.txt
Now I am using PowerShell to initially order these files so that the top of the list is the most recent file in the folder:
d-002.txt
b-002.txt
a-001.txt
a-002.txt
b-001.txt
d-001.txt
EDIT: I then store the top X recent number of files into a variable. However, I want to ignore anything that starts with A if I already have one that begins with A in my array but still ensure I end up with X files which are the most recent. I.e. from above, I would want to end up with below if X was 4.
d-002.txt
b-002.txt
a-001.txt
b-001.txt
This is a simple example, the folders I am dealing with contain 1000s of files - with more complex naming conventions but the logic is the same. How can I handle this in PowerShell?
Removing the logic for any other Sort-Object and Select-Object criteria as you already have that addressed I present the following.
Get-ChildItem $somePath | Select-Object *,#{Label="Prefix";Expression={(($_.Name) -Split "-",2)[0]}} | Group-Object prefix | ForEach-Object{
$_.Group | Select-Object -First 1 -Property Fullname
}
What happens here is that we add a property to the output of Get-ChildItem called "Prefix". Now, your criteria might be more complicated but given the sample I assumed the files were being grouped by the contents of the name before the first "-". So we take every file name and build its prefix based on that. The magic comes from Group-Object which will group all items and then we just select the first one. In your case that would be the newest X amount. Let me know if you are having trouble integrating this.
Aside from grouping logic any sorting an what not would need to exists before the Select-Object in our example above.
FYI for other readers
There were issues with OP's actual data since the above code didnt work exactly. We worked it out in chat and using the same logic we able to address the OPs concern. The test data in the question and my answer work as intended.