Do you need to find duplicate elements from an array in PowerShell? In this PowerShell tutorial, I will explain how to find duplicates in an array in PowerShell using various methods and examples.
In PowerShell, you can create an array by assigning multiple values to a single variable, separated by commas.
$myArray = "apple", "banana", "cherry", "apple", "banana"In the above example, $myArray is an array that contains five items, including some duplicates. Now, let us check various methods to find duplicate items from a PowerShell array using different methods.
Method 1: Using Group-Object
The Group-Object cmdlet is a straightforward way to group objects in PowerShell. When it comes to arrays, you can use it to group similar items and count them. To find duplicates, you can filter these groups to find any that have a count greater than one.
Here’s an example:
$myArray = "apple", "banana", "cherry", "apple", "banana"
$duplicates = $myArray | Group-Object | Where-Object { $_.Count -gt 1 }
$duplicates | Foreach-Object { $_.Name }This script will output apple and banana, because these are the items that appear more than once in the array. You can see the output in the screenshot below:

Method 2: Using Select-Object
Another method involves using the Select-Object cmdlet with the -Unique switch, which filters out duplicate entries. This method is useful if you want to see the unique values of a PowerShell array. However, to find duplicates, you must compare the unique array with the original.
Here’s how you can do that:
$myArray = "apple", "banana", "cherry", "apple", "banana"
$unique = $myArray | Select-Object -Unique
$duplicates = $myArray | Where-Object { $unique -notcontains $_ }In this script, $unique will contain all unique elements, and $duplicates will have the duplicates after comparing with the original array.
Method 3: Using Custom Comparison
You can also write custom script to find duplicates from a PowerShell array, you can write a script that iterates over the array and checks for duplicates by keeping track of items that have already been seen.
Here’s a custom script to find duplicates:
$myArray = "apple", "banana", "cherry", "apple", "banana"
$seen = @{}
$duplicates = @()
foreach ($item in $myArray) { if ($seen[$item]) { $duplicates += $item } else { $seen[$item] = $true }
}
$duplicates = $duplicates | Select-Object -Unique
$duplicatesThis script uses a hashtable $seen to keep track of items that have been iterated over. If an item is already in the hashtable, it is added to the $duplicates array. Finally, we filter $duplicates to only unique values since the same duplicate could be added multiple times.
You can see the output in the screenshot below:

Method 4: Using LINQ in PowerShell
For those who are a bit more advanced and are familiar with .NET, PowerShell can leverage LINQ (Language-Integrated Query) to find duplicates. This is a more complex method but can be very efficient for large datasets.
$myArray = "apple", "banana", "cherry", "apple", "banana"
$duplicates = [System.Linq.Enumerable]::ToLookup([object[]]$myArray, [Func[object, object]]{param($i) $i}) | Where-Object { $_.Count -gt 1 } | Foreach-Object { $_.Key }This script converts the array into a lookup, where each item is a key, and filters out the keys with more than one occurrence, which indicates duplicates.
Conclusion
Finding duplicates in an array is easy and possible in various ways in PowerShell; you can use Group-Object, Select-Object, a custom comparison script, or even LINQ.
In this post, I have explained how to find duplicates in an array in PowerShell using various methods.
You may also like:
Do you need to compare two arrays to find matches in PowerShell? In this article, we’ll explore different methods to compare two arrays for matches in PowerShell with complete examples.
To compare two arrays for matches in PowerShell, you can use the Compare-Object cmdlet with the -ReferenceObject and -DifferenceObject parameters to identify similarities. Alternatively, loop through one array and use the -contains operator to check if each item exists in the second array. For a more concise approach, leverage LINQ’s Intersect method to find common elements directly.
Now, let us check out how to compare two arrays for matches in PowerShell.
Method 1: Using Loops
The most basic method to compare two arrays is by using loops to iterate through each element and check for matches in PowerShell.
$array1 = @('apple', 'banana', 'cherry')
$array2 = @('banana', 'kiwi', 'apple')
foreach ($item1 in $array1) { foreach ($item2 in $array2) { if ($item1 -eq $item2) { Write-Output "Match found: $item1" } }
}In this example, we have two arrays $array1 and $array2, and we use nested foreach loops to iterate through each element. If an element from $array1 matches an element from $array2, we output the match.
You can see the output in the screenshot below after I executed the VS code.

Method 2: Using -contains Operator
A more efficient way to find matches is to use the -contains operator, which checks if a single value is present in an array in PowerShell.
$array1 = @('apple', 'banana', 'cherry')
$array2 = @('banana', 'kiwi', 'apple')
foreach ($elem in $array1) { if ($array2 -contains $elem) { Write-Output "Match found: $elem" }
}This method is more straightforward and faster than using nested loops, as it eliminates the need for the inner loop.
Method 3: Using Compare-Object Cmdlet
PowerShell provides a cmdlet called Compare-Object that compares two sets of objects. It’s a powerful tool that can show differences as well as similarities between arrays in PowerShell.
$array1 = @('apple', 'banana', 'cherry')
$array2 = @('banana', 'kiwi', 'apple')
$comparison = Compare-Object -ReferenceObject $array1 -DifferenceObject $array2 -IncludeEqual
foreach ($result in $comparison) { if ($result.SideIndicator -eq '==') { Write-Output "Match found: $($result.InputObject)" }
}The Compare-Object cmdlet uses -ReferenceObject and -DifferenceObject parameters to specify the arrays to compare. The SideIndicator property tells us whether the object is present in both arrays (==), only in the reference array (<=), or only in the difference array (=>).
You can see this in the screenshot below:

Method 4: Using LINQ
For those who are familiar with .NET, PowerShell can leverage the LINQ (Language Integrated Query) to compare arrays.
$array1 = @('apple', 'banana', 'cherry')
$array2 = @('banana', 'kiwi', 'apple')
$matches = [System.Linq.Enumerable]::Intersect($array1, $array2)
foreach ($match in $matches) { Write-Output "Match found: $match"
}Here, we use the Intersect method from the System.Linq.Enumerable class to find common elements between $array1 and $array2.
Conclusion
Comparing arrays for matches in PowerShell can be done using different methods. You can use the simple loops and the -contains operator to understand the basics of array comparison in PowerShell. As you become more comfortable with PowerShell, you can use more advanced methods like Compare-Object or LINQ to perform the same task more efficiently.
In this PowerShell tutorial, I have explained how to compare two arrays for matches in PowerShell using various methods and examples.
You may also like:
Using PowerShell to Get a Report of Installed Apps
Every time we do an Intune deployment, especially for clients who come from SCCM or other platforms, we are asked to provide some means to examine details of managed devices. As we all know, Intune reporting is a bit “basic,” so in this article, I walk through the steps to use PowerShell to obtain the information commonly requested by clients to support their operations.
Intune PowerShell Modules
Currently, two PowerShell modules can be used. The first is the Intune PowerShell module; the second is the Microsoft Graph PowerShell SDK, which includes the device management and applications sub-modules. Microsoft doesn’t maintain the Intune PowerShell module anymore and I recommend that you use the Microsoft Graph PowerShell SDK one, which Microsoft actively maintains to aligned with the latest release of Graph APIs.
The scripts we develop using the Graph SDK are more future-proofed and it will be easier to add new features along the road. Another benefit from using the Graph SDK is that it works for non-Windows devices, which is handy for people like me who use macOS devices as their primary workstation.
To start, we must connect the Graph API endpoint using Connect-MgGraph cmdlet. In case you need it, here are the steps to install the Microsoft Graph PowerShell module, and some advice about different means to authenticate and connect to the Microsoft Graph PowerShell modules is available found here. Note that we just need to install Microsoft.Graph PowerShell modules as the rest will be loaded on-demand when needed.
Connect-MgGraph -Scopes "DeviceManagementApps.Read.All","DeviceManagementManagedDevices.Read.All"
- DeviceManagementApps.Read.All
- DeviceManagementManagedDevices.Read.All
Now we are ready to gather data about devices. I will separate the sections into the different types of reports we usually generate.


Get List of Applications for Managed Devices
Clients often ask for a report about managed applications and versions and expect that the report includes both MAM and MDM managed applications . The Graph SDK cmdlets you need are use are:
- Get-MgDeviceManagementDetectedApp (MDM application data covering Windows, macOS, iOS, and Android)
- Get-MgDeviceAppManagementManagedAppRegistration (MAM).
Here’s some example code that I use to pull a report of all apps from mobile devices managed by Intune MAM (including Azure AD joint device):
$result=@ ()
Get-MgDeviceManagementDetectedApp -All | ForEach-Object {
$tmp=$_
$result+=(Get-MgDeviceManagementDetectedAppManagedDevice -DetectedAppId $_.id | Select-Object -Property @{Name=”Device”;Expression={$_.DeviceName}},
@{Name=”App”;Expression={$tmp.DisplayName}},
@{Name=”Version”;Expression={$tmp.Version}},
@{Name=”Platform”;Expression={$tmp.platform}})
}
$result | Sort-Object -Property Device, App, Version | Out-GridViewThe result looks like the output shown in Figure 2.

Let me explain the script flow:
- We define an empty array called tmp to store the result.
- Use Get-MgDeviceManagementDetectedApp -All to get all the detected app from Intune.
- The ForEach-Object cmdlet processes the app data and calls Get-MgDeviceManagementDetectedAppManagedDevice using the ID for each app record we obtained from the previous step.
- Inside the foreach loop, the script selects the required properties from the result and constructs a custom object.
- The script then uses Sort-Object to sort the output according to your needs.
- Finally, the script displays the data using Out-GridView. You can also use another cmdlet like Export-Csv to output to a CSV file.
Get List of Applications for Managed Apps
We can use Get-MgDeviceAppManagementManagedAppRegistration to fetch MAM registration information (figure 3). Registration information means the apps registered in Intune MAM.

However, some data that this cmdlet returns may not be in a meaningful format, as illustrated in Figure 4. Result data does not include the application name and outputs an object type name. You may need to add logic to handle this kind of situations to obtain the underlying data. For example, try to use Select-Object -ExpandProperty to expand the data or create custom objects as part of your PowerShell script.

According to the Microsoft’s documentation, the app identifier should show the application’s ID, like com.microsoft.office.outlook.ios. But it’s not showing needed info, instead it is showing object type names like Microsoft.Graph.PowerShell.Models.MicrosoftGraphMobileAppIdentifier, and this makes us unable to make good use of the data returned.
Further Processing the Data
$users=Get-MgUser -All -Filter "assignedLicenses/`$count ne 0 and userType eq 'Member'" $mam=Get-MgDeviceAppManagementManagedAppRegistration -All Join-Object -Left $mam -Right $users -LeftJoinProperty "UserId" -RightJoinProperty "Id" -ExcludeLeftProperties "CreatedDateTime","AdditionalProperties" -RightProperties "DisplayName" | Out-GridView

- Gets the licensed user list from Get-MgUsers and stores in variable.
- Gets the Intune MAM registration information using Get-MgDeviceAppManagementManagedAppRegistration and stores in variable.
- Uses Join-Object cmdlet to do a SQL-like join with UserId properties and only includes needed field Display Namse from data collected in step 1.
- Displays the result in Out-GridView

Unlimited Possibilities for Graph Reporting
With the help of Join-Object cmdlet, you can easily combine data retrieved using different PowerShell cmdlets instead of exporting data to CSV and using Excel to do the massaging. But note that processing like Join-Object happens in memory, so make sure you have enough free memory. You can check the free memory information by looking at Task Manager and see how much memory is consumed by pwsh.exe and how much free memory is available in your system.
How to execute PowerShell script or cmdlets from C# code?
| System | |
| SystemCollectionsGeneric | |
| SystemCollectionsObjectModel | |
| SystemDiagnostics | |
| SystemLinq | |
| SystemManagementAutomation | |
| SystemText | |
| SystemThreading | |
| SystemThreadingTasks | |
| PowerShell | |
| PowerShellInstGet-Service -DisplayName | |
| PowerShellInst | |
| PSObject obj PSOutput | |
| ConsoleobjPropertiesValue | |
| ConsoleobjPropertiesValue | |
| Console | |
| Console | |
| System | |
| SystemCollectionsGeneric | |
| SystemCollectionsObjectModel | |
| SystemDiagnostics | |
| SystemLinq | |
| SystemManagementAutomation | |
| SystemText | |
| SystemThreading | |
| SystemThreadingTasks | |
| //Execute PS1(PowerShell script) file | |
| PowerShell | |
| SystemIOPath | |
| path | |
| PowerShellInstSystemIOFilepath | |
| PowerShellInst | |
| PSObject obj PSOutput | |
| ConsoleobjPropertiesValue | |
| ConsoleobjPropertiesValue | |
| ConsoleobjPropertiesValue | |
| Console | |
| Console | |
| System | |
| SystemCollectionsGeneric | |
| SystemCollectionsObjectModel | |
| SystemDiagnostics | |
| SystemLinq | |
| SystemManagementAutomation | |
| SystemText | |
| SystemThreading | |
| SystemThreadingTasks | |
| //execute powershell cmdlets or scripts using command arguments as process | |
| ProcessStartInfo | |
| processInfoFileName | |
| //execute powershell script using script file | |
| //execute powershell command | |
| processInfoArguments | |
| processInfoRedirectStandardError | |
| processInfoRedirectStandardOutput | |
| processInfoUseShellExecute | |
| processInfoCreateNoWindow | |
| //start powershell process using process start info | |
| Process | |
| processStartInfo | |
| process | |
| Console processStandardOutput | |
| Console processStandardError | |
| Console | |
By the end, you’ll be familiar with several .NET classes and understand how to discover and use others that might better meet your specific needs.
Why use .NET classes in PowerShell?
There are two main reasons:.
- Extended Functionality: Access features in .NET not available natively in PowerShell.
- Enhanced Performance: Many .NET classes perform faster than their PowerShell equivalents.
Exploring .NET also helps deepen your understanding of the foundation upon which PowerShell is built.
Determining what version of .NET CLR PowerShell is using
Different .NET/Core versions support different classes and behaviors. Knowing the .NET CLR (Common Language Runtime) version PowerShell is using helps you refer to the correct documentation and troubleshoot unexpected behaviors.
PowerShell 5.1 uses .NET Framework 4.0.30319.42000.
C:\> PSVersionToString
51190413996 C:\> ::VersionToString
403031942000PowerShell 7.4.1 uses .NET Core 8.0.1
C:\> PSVersionToString
741 C:\> ::VersionToString
801We can already see a big difference here, v5.1 uses the older .NET Framework while 7.x uses the more modern .NET Core. This is why PowerShell 7.x can be cross platform, and why it can’t ship with Windows as Microsoft does not want to bundle the .NET Core runtime due to support lifecycles of the products being different (at least that is my understanding).
There will be an example below where the .NET CLR version is important.
Let’s begin with something simple, validating whether a string is null, empty, or whitespace.
String validation
.NET has very two very convenient string validation methods built into the String class, IsNullOrEmpty, and IsNullOrWhiteSpace. While not difficult, performing this kind of validation in PowerShell 5.1 requires a bit more work than just calling a method.
Here are a few examples:
= = = =
::IsNullOrEmpty
::IsNullOrEmpty
::IsNullOrEmpty
::IsNullOrEmpty
::IsNullOrWhiteSpace
::IsNullOrWhiteSpace
::IsNullOrWhiteSpace
::IsNullOrWhiteSpaceIsNullOrEmpty
True
True
False
False
IsNullOrWhiteSpace
True
True
True
FalseString validation natively in PowerShell
PowerShell 5.1 has ValidateNotNullOrEmpty built in, while PowerShell 7 contains both validators in the form of attributes. Here is an example:
= # Works in PowerShell 5.1+ = # Works in PowerShell 7+Using the .NET method however works across all versions.
Moving on, let’s tackle IP address validation
IP Address validation using [IPAddress]
C:\>
Address : 16843018
AddressFamily : InterNetwork
ScopeId :
IsIPv6Multicast : False
IsIPv6LinkLocal : False
IsIPv6SiteLocal : False
IsIPv6Teredo : False
IsIPv4MappedToIPv6 : False
IPAddressToString : 10111However, it has limitations; for example, 10.1 is considered a valid value:
C:\>
Address : 16777226
AddressFamily : InterNetwork
ScopeId :
IsIPv6Multicast : False
IsIPv6LinkLocal : False
IsIPv6SiteLocal : False
IsIPv6Teredo : False
IsIPv4MappedToIPv6 : False
IPAddressToString : 10001However, we can get around this by comparing the input against the IPAddressToString output:
IPAddressToStringHere are some examples:
C:\> @ IPAddressToString
True
False
False
False
InvalidArgument: Cannot convert value to Error: "An invalid IP address was specified."InvalidArgument: Cannot convert value to Error: "An invalid IP address was specified."InvalidArgument: Cannot convert value to Error: "An invalid IP address was specified."The second value of 10.1 while accepted as valid input for the class failed the equality check, and the same goes for the third hex value and the fourth decimal value. Both are ‘valid’ input for the class as they’re just different ways a valid IP can be represented, but if we’re expecting the usual dotted-decimal IP representation in our input they fail the string equality check.
The last three are invalid IP addresses and return errors.
While we’re on the topic of networking, let’s look at MAC Addresses.
MAC Address Validation and Normalisation using [PhysicalAddress]
As with IP addresses we can use regex and some string manipulation here, but .NET again has a convenient method to make our code a little cleaner and easier to read.
Valid MAC address example:
C:\> ::Parse
34ED1BAABBCCInvalid MAC address example:
C:\> ::Parse
Exception calling with arguments: "An invalid physical address was specified."At line:1 char:1 ::Parse ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ CategoryInfo : NotSpecified: : MethodInvocationException FullyQualifiedErrorId : FormatExceptionCompatibility Across .NET Versions
If you recall earlier the underlying version of .NET CLR can make a difference, this the is one class where Microsoft has made improvements between .NET Framework (used by PowerShell 5.1) and .NET Core.
Unfortunately the above format (all uppercase, - delimited) is the only format valid under .NET Framework. All of these valid and commonly formatted MAC address values fail:
C:\> ::Parse
Exception calling with arguments: "An invalid physical address was specified." C:\> ::Parse
Exception calling with arguments: "An invalid physical address was specified." C:\> ::Parse
Exception calling with arguments: "An invalid physical address was specified."However, they all work under PowerShell 7.x which is built on top of .NET Core.
C:\> ::Parse
34ED1BAABBCC C:\> ::Parse
34ED1BAABBCC C:\> ::Parse
34ED1BAABBCCThese changes are documented in the Microsoft documentation.

Sticking with the networking theme, let’s test TCP ports
Fast TCP port testing with [System.Net.Sockets.TcpClient]
This is one of my favourites simply because it’s so much faster than Test-NetConnection thanks to the configurable timeout.
Here is an example:
C:\> = C:\> = 443 C:\> = 100 C:\> = ::New C:\> ConnectAsyncWait
True C:\> DisposeIt returns $true if the connection was successfully established, and $false if not.
Generating passwords with [System.Web.Security]
I’m sure at some stage we’ve all needed to programmatically generate passwords. The System.Web.Security namespace has a nice method for doing this. The downside is that it did not make it across to .NET Core, so it only works on PowerShell 5.1.
The syntax is GeneratePassword (int length, int minimumNumberOfNonAlphanumericCharacters)
Here are a couple of examples:
C:\> ::GeneratePassword201
7!=vvIOh45ib3p+dU&AGSvHy42+ C:\> ::GeneratePassword2010
g2Ht@AM-pv&iz+dNULet’s move onto some .NET classes that have a wider use cases.
Using List instead of PowerShell Arrays
Before we go further let’s quickly cover using statements.
‘Using’ statements
‘Using’ statements allow us to use types without having to reference the entire namespace each time we want to interact with the class. For example, if we wanted to create a List<T> (a .NET class we will cover below) we can do so in two ways.
The first is to specify the full namespace path:
= ::NewThe second is to place a using statement at the top of the script, and then reference the type only by its name.
namespace SystemCollectionsGeneric = ::NewWe already have a similar concept to this in PowerShell. We can run Get-Process by itself, or we can reference the module-qualified cmdlet with Microsoft.PowerShell.Management\Get-Process. If we had two commands that mapped to Get-Process we could remove ambiguity by writing out the full path.
Back to using List<T>.
List<T> in PowerShell
However, when we attempt to perform some task against each item in the collection (as is common) we’re likely to encounter errors.
C:\> @1020 2
5
10
InvalidArgument: Cannot convert value to Error: "The input string 'thirty' was not in a correct format."With generics we specify what type will be contained inside the collection. Let’s begin with creating a List<T> to hold integers.
namespace SystemCollectionsGeneric = ::New
Add10
Add20Now when we add “thirty” we will receive an error.
C:\> Add
MethodException: Cannot convert argument with value: to : "Cannot convert value "thirty" to type "SystemInt32". Error: "The input string was not in a correct formatList Caveats
= ::New
Add
Add
Add30Here the integer 30 was automatically cast to the string "30".
C:\>
ten
twenty
30 C:\> 2GetType
IsPublic IsSerial Name BaseType
True True String SystemObjectThis appears to be a PowerShell specific behaviour as the equivalent C# code will throw an exception.
Numbers
Numbers
Numbers
NumbersError CS1503 Argument cannot convert from '' to ''Another caveat is that List<T> accepts null values regardless of the type specified.
C:\> = ::New C:\> Add C:\>
0 C:\> = ::New C:\> Add C:\> Count
1Setting aside tangents and caveats, List<T> vastly outperforms PowerShell arrays, offering significant performance improvements.
.NET Syntax in PowerShell
We have explored several .NET classes, which might raise questions about their syntax in PowerShell.
Understanding [ClassName]::MethodName() Syntax
Here it is shown in the Microsoft documentation for the PhysicalAddress class.

When we use the usual . notation to invoke a method (as we did with $List.Add()) this the same as invoking a method on a PowerShell object, for example $SomeString.ToUpper().
Default imports
C:\> ::CurrentDomainGetAssemblies ? Location
GAC Version Location
False v4030319 C:\Program Files\PowerShell\7\SystemCollectionsdll
False v4030319 C:\Program Files\PowerShell\7\SystemCollectionsConcurrentdll
False v4030319 C:\Program Files\PowerShell\7\SystemCollectionsSpecializeddll
False v4030319 C:\Program Files\PowerShell\7\SystemCollectionsNonGenericdll
False v4030319 C:\Program Files\PowerShell\7\SystemCollectionsImmutabledll C:\> ::New
InvalidOperation: Unable to find In short, some namespaces will be imported by default, others you’ll need to specify even if the assembly is loaded.
Microsoft’s documentation is an excellent resource for mapping classes to namespaces and assemblies.

And here is a list of all classes in the System.Collections.Generic namespace. I will briefly cover HashSets, but I’d recommend exploring others as a learning exercise.
Loading custom or third party assemblies
Sometimes the classes we want to work with are in third party assemblies. We can load these using Add-Type. As this is slightly out of scope for this post and I’ve shown examples of it before, you can check it out here.
Using LINQ in PowerShell
LINQ (Language Integrated Query) is a .NET component that allows for data querying and filtering. Think of a combination PowerShell’s Where, Measure-Object, and Select cmdlets, but usually a lot faster than native PowerShell cmdlets, especially when dealing with large collections.
Let’s look at a couple of simple examples.
List comparison with LINQ in PowerShell
We’re going to create a few lists and compare their contents with LINQ, including the order of the items in the lists.
= = = # Same items, different order::SequenceEqual
::SequenceEqual # False due to ordering being differentThere is a Sort method we can use if we have lists where the items may have different ordering:
::SequenceEqual
::SequenceEqual Getting minimum, maximum, average values from a collection
= ::new
1100 Add Minimum 1 Maximum 1000 C:\> ::Min
32 C:\> ::Max
983 C:\> ::Average
51395 C:\> ::Sum
51395As a very quick performance comparison let’s see how LINQ compares with Measure-Object for calculating the sum of one million numbers.
= ::new
11000000 Add Minimum 1 Maximum 100 C:\> 110 Sum ExpandProperty TotalMilliseconds Average
Average : 85756657 C:\> 110 ::Sum ExpandProperty TotalMilliseconds Average
Average : 045215In this example LINQ is ~1897 times faster than piping to Measure-Object
There are too many LINQ methods to cover here, and I’ve only scratched the surface to show the most basic syntax. Michael Sorens has written a fantastic article on using LINQ with PowerShell titled High Performance PowerShell with LINQ that I recommend you check out.
Listing Available Methods and Properties of .NET Classes
If you’re wondering what other static methods LINQ has, you may have tried to pipe the class to Get-Member. You may have also tried to do the same for a List<T> object and found unexpected results.
What you’ll find with collections like List<T> is Get-Member returns data of the type of the first item inside the collection.
C:\> = ::new C:\>
: You must specify an object the cmdlet C:\> Add1 C:\> TypeName: SystemInt32
Name MemberType Definition
CompareTo Method int CompareToSystemObject value int CompareToint value int IComparableCompareToSystemObject obj int IComparableCompareToint other
Equals Method bool EqualsSystemObject obj bool Equalsint obj bool IEquatableEqualsint other
GetByteCount Method int IBinaryIntegerGetByteCount
GetHashCode Method int GetHashCode
GetShortestBitLength Method int IBinaryIntegerGetShortestBitLengthWe can use GetMembers() to get the list of methods and properties. When calling it on an already instantiated object we first need to bubble up the class using GetType(), and then call GetMembers().
C:\> C:\> GetTypeGetMembers ? MemberType ExpandProperty Name Unique
get_Capacity
set_Capacity
get_Count
get_Item
set_Item
Add
AddRange
AsReadOnly
BinarySearch
Clear
Contains
ConvertAll
CopyTo
EnsureCapacity
Exists
FindIf calling it on a type, we can omit the GetType() call. Here are some of the LINQ methods available:
C:\> GetMembers ? MemberType ? IsStatic ExpandProperty Name Unique
Empty
Aggregate
Any
All
Append
Prepend
Average
OfType
Cast
Chunk
Concat
Contains
Count
TryGetNonEnumeratedCount
LongCount
DefaultIfEmpty
Distinct
DistinctBy
ElementAt
ElementAtOrDefault
AsEnumerable
Except
ExceptBy
FirstUsing LINQ with other .NET collection types
LINQ works with any collection class that implements IEnumerable<T>, not just lists. So what is IEnumerable<T> and how do we find out what “implements” it?
.NET Interfaces
Interfaces are a contractual blueprint for classes that define what methods and properties implementing classes must provide. The classes that implement that interface then define how those members are implemented.
For example, we could have an IAnimal interface (the convention for interface naming is to begin with a capital I) which states that any classes implementing it must have a MakeNoise method that returns a string (e.g., “Woof”).
When we then create our various animal classes we make them implement the IAnimal interface, and in each animal class we will need to write the MakeNoise method (or we will get IDE / compilation errors) and have it return the noise of that specific animal.
Using interfaces means we can have confidence that regardless of the animal, there will be a MakeNoise method that returns a string. There are other advantages to interfaces such as decoupling which helps facilitate changes but none of that is important for our needs here.
Back to LINQ – it works with classes that implement the IEnumerable<T> interface. How do we find what those are?
There are two ways in PowerShell.
GetInterfaces
We can use the GetInterfaces method:
C:\> GetInterfaces
IsPublic IsSerial Name BaseType
True False IList`1
True False ICollection`1True False IEnumerable`1True False IEnumerable
True False IList
True False ICollection
True False IReadOnlyList`1
True False IReadOnlyCollection`1We can see List<T> list implements both IEnumerable and IEnumerable'1, so what’s the difference? The the backtick and digit indicates this is a generic type (List<T> instead of just List) and refers to the number of type parameters it accepts.
For example, List<T> only accepts one, but a Dictionary<T key,T value> accepts two (one for the key and one for the value), as seen below:
C:\> GetInterfaces
IsPublic IsSerial Name BaseType True False IDictionary`2True False ICollection`1
True False IEnumerable`1
True False IEnumerable
True False IDictionary
True False ICollection
True False IReadOnlyDictionary`2
True False IReadOnlyCollection`1
True False ISerializable
True False IDeserializationCallbackPowerShell native arrays only implement IEnumerable, not IEnumerable<T>, so they don’t work with LINQ without casting (more on this below).
C:\> GetInterfaces
IsPublic IsSerial Name BaseType
True False ICloneable
True False IList
True False ICollectionTrue False IEnumerableTrue False IStructuralComparable
True False IStructuralEquatableLet’s try it out:
C:\> = @123456789 C:\> ::Sum
MethodException: Cannot find an overload and the argument count: The second method to determine whether something implements an interface is to use IsAssignableFrom.
IsAssignableFrom
First we need to define our type, then the interface, and then call the IsAssignableFrom method.
C:\> = C:\> = C:\> IsAssignableFrom
TrueLet’s check PowerShell arrays.
C:\> = C:\> = C:\> IsAssignableFrom
FalseWe can also check the class documentation.
Documentation
Here is a screenshot showing what interfaces List<T> implements.
![List<T> interfaces” title=”” src=”https://xkln.net/static/e70d03a18219d8c611456685b5daaa2c/8c557/list-interfaces.png” srcset=”https://xkln.net/static/e70d03a18219d8c611456685b5daaa2c/4edbd/list-interfaces.png 175w,<br /> https://xkln.net/static/e70d03a18219d8c611456685b5daaa2c/13ae7/list-interfaces.png 350w,<br /> https://xkln.net/static/e70d03a18219d8c611456685b5daaa2c/8c557/list-interfaces.png 700w,<br /> https://xkln.net/static/e70d03a18219d8c611456685b5daaa2c/69476/list-interfaces.png 926w” sizes=”(max-width: 700px) 100vw, 700px” loading=”lazy” decoding=”async”></p><p>Let’s cover casting PowerShell arrays to an object that enables us to use LINQ.</p><h2>Casting PowerShell arrays to an IEnumerable<T> object</h2><p>We may already have an existing array that we would like to use with LINQ, and in these cases LINQ provides a casting method that returns a usable objects which implements <code>IEnumerable<T></code>.</p><pre><code> = @1 2 3 4 5 = ::Cast<span># We can now use LINQ</span> C:\> ::Average
3 C:\> GetType
IsPublic IsSerial Name BaseType
False False <CastIterator>d__68`1 SystemObject</code></pre><p>Let’s move onto the final .NET class for this post: HashSets</p><h2>.NET HashSet<T> in PowerShell</h2><p>A <code>HashSet<T></code> is another generic .NET collection class similar to a <code>List<T></code> with a few notable differences.</p><ol><li>It is unordered (though there is also a <code>SortedSet<T></code>)</li><li>All items in the HashSet must be unique (no duplicates)</li><li>It cannot be indexed into using <code>$HashSet[<int>]</code></li></ol><p>As we’re now familiar with most of the syntax, let’s jump straight into the examples:</p><p>Creating the <code>HashSet<T></code> object:</p><pre><code> namespace SystemCollectionsGeneric = ::New</code></pre><p>Adding, searching for, and removing items:</p><pre><code><span># Adding an item</span> C:\> Add1
True<span># Checking if the set contains an item</span> C:\> Contains1
True<span># Duplicates are not permitted</span> C:\> Add1
False<span># Removing an item</span> C:\> Remove1
True</code></pre><p>As <code>HashSet<T></code> implements <code>IEnumerable<T></code> we can use LINQ without any casting. Let’s look at slightly more complex example than before. We’re going to create two HashSets, the first will be a set of IP addresses we “trust”. The second will be a list of IP addresses perhaps pulled from some access logs. What we want to do is return a collection of unique IPs in the second set, but exclude the “trusted” IPs from the first set.</p><p><img alt=](https://xkln.net/static/272ab378ef7de3acf2efc933664aca99/a2d48/hashset-venn.png)
namespace SystemCollectionsGeneric = ::New \trustedtxt = ::New \accesslogtxtHere are the contents of those two files:
102501100
102501101
192168150
102501120
102501100
215714595
102501100
102501100
102501100
125286035
125286035We can see our accesslog file has several duplicates, but once we add it to our set the duplicate values are no longer present.
C:\> ExpandProperty IPAddressToString
192168150
102501120
102501100
215714595
125286035Now let’s use LINQ to extract the logged IPs but exclude our trusted addresses.
C:\> = ::Except C:\> Expand IPAddressToString
192168150
102501120
215714595
125286035That wraps it up. Hopefully you’ve not only discovered some useful .NET classes but also have a bit of insight into how to find and use other types that haven’t been covered here.
System.Object[]
Note that the assignment by addition operator doesn’t technically append any items to the original array – it returns a new array that contains the result of concatenating the two operands:
# make two references to the original array
$s1 = 1..5
$s2 = $s1
[object]::ReferenceEquals($s1, $s2)
# True
# "add" more values to the array - note this will actually create a new array instance that contains 1..10
$s1 += 6..10
[object]::ReferenceEquals($s1, $s2)
# False
# the new instance contains 1..10
$s1.Length
# 10
# but the original array still only contains values 1..5
$s2.Length
# 5 You can do something similar for “subtraction” using the range operator to concatenate the items before the indices you want to remove and the items after the indices you want to remove:
$s1 = 1..10
# "remove" items at index 5-7 (i.e. values 6-8) by concatenating items
# at 0..4 and 8..9 into another new array
$s1 = $s1[0..4] + $s1[8..9]
$s1
# 1
# 2
# 3
# 4
# 5
# 9
# 10System.ArrayList
In general though, it’s more efficient to use a mutatable type like an ArrayList if you plan to perform lots of “addition” and “subtraction” operations as creating copies of arrays during each operation can be computationally expensive (cpu and memory) if you do it repeatedly or with very large arrays.
# create a new arraylist containing the values 1..5
$s1 = [System.Collections.ArrayList]::new(1..5)
$s1.Count
# 5
# append the additional items to the list
$s1.AddRange(6..10)
$s1.Count
# 10
# remove items at indices 5-7
$s1.RemoveRange(5, 3)
$s1
# 1
# 2
# 3
# 4
# 5
# 9
# 10Note the use of Count rather than Length for an ArrayList.
Linq
$s1 = 1..10
$s1 = [System.Linq.Enumerable]::Where( $s1, [Func[object, int, bool]] { param($item, $index) ($index -lt 5) -or ($index -gt 7) }
)
$s1
# 1
# 2
# 3
# 4
# 5
# 9
# 10Вот вопросы и ответы на собеседовании по PowerShell для новичков, а также для опытных кандидатов, желающих получить работу своей мечты.
1) Объясните, что такое PowerShell?
Power Shell — это расширяемая командная оболочка и язык сценариев для Windows.
2) Каковы ключевые характеристики PowerShell?
Ключевые характеристики PowerShell:
- PowerShell основан на объектах, а не на тексте.
- Команды в PowerShell можно настраивать.
- Это интерпретатор командной строки и среда сценариев.
Бесплатная загрузка в формате PDF: Вопросы и ответы на собеседовании по PowerShell
3) Что содержат переменные в PowerShell?
В переменных PowerShell содержатся строки, целые числа и объекты. Он не имеет специальных переменных, поскольку он предварительно определен в PowerShell.
4) Объясните, какое значение имеют скобки в PowerShell?
- Круглые скобки (): Круглые скобки в виде изогнутых скобок используются для обязательных аргументов.
- Фигурные скобки Скобки {} : Фигурные скобки используются в заблокированных операторах.
- Квадратные скобки []: Они определяют необязательные элементы и используются нечасто.
5) Что означает командлет?
Командлеты — это простые встроенные команды, написанные на .net язык, такой как C# или VB, представленный Windows PowerShell
6) Объясните, что такое цикл PowerShell?
Автоматизация повторяющихся задач с помощью цикла PowerShell известна как цикл PowerShell. С помощью PowerShell вы можете выполнить цикл For каждого, цикл While и цикл Do While.
7) Объясните, можете ли вы создавать сценарии PowerShell для развертывания компонентов в SharePoint?
Если вы создали веб-часть с помощью VS 2010, вы можете развернуть ее, используя cntrl+f5. Однако для активации функции веб-части вы можете написать сценарий PowerShell (.ps1) и выполнить его после развертывания.
8) Расскажите об операторах сравнения PowerShell?
Операторы сравнения сравнивают значения в PowerShell. Используются четыре типа операторов сравнения. равенство, совпадение, сдерживание и замена. В PowerShell одним из ключевых операторов сравнения является –eq, который используется вместо знака «=» при объявлении переменных. Аналогично, существуют и другие операторы, такие как –ne для «не равно», –gt (больше чем) или –lt (меньше чем).
9) Объясните, для чего используется конвейер PowerShell?
Конвейер PowerShell используется для объединения двух операторов, при котором выходные данные одного оператора становятся входными данными второго.

10) Объясните, что такое get-команда PowerShell?
Команда Get в PowerShell используется для получения других командлетов, например, вы ищете командлет между буквами L и R, тогда ваша команда get PowerShell будет выглядеть так:
# PowerShell Get - Command Range Clear-Host Get-Command [ L–R ]*
11) Объясните на примере, как можно подключить сетевой диск в PowerShell?
Чтобы подключить сетевой диск в PowerShell, вам нужно использовать команду типа
# PowerShell Map Network Drive $Net = $( New - Object – ComObject Wscript.Network ) $Net.MapNetworkDrive( "S:", \\expert\guru99 )
Здесь буква диска — «S:», а сетевой ресурс называется «expert» на компьютере с именем «guru99».
12) Укажите, какие три способа PowerShell использует для «Выбора»?
- Самый распространенный способ – это Язык запросов WMI (WQL) заявление. В этом методе Wmiobject использует ‘-query’ для введения классического ‘Выберите из’ фраза
- Второй контекст для «Выбрать» в PowerShell: Выбрать строку. Этот командлет проверяет совпадение слова, фразы или любого шаблона.
- Другой способ Выбрать объект
13) Какова функция статуса Get-Service в PowerShell?
Командлет Windows позволяет фильтровать оконные службы. PowerShell может перечислить, какие службы «работают», а какие «остановлены», с помощью сценариев с помощью Windows.
14) Объясните, что такое сценарии PowerShell?
Файл PowerShell содержит ряд команд PowerShell, каждая из которых отображается на отдельной строке. Чтобы использовать текстовый файл в качестве сценария PowerShell, его имя должно иметь расширение .PS1. Для запуска скрипта вам нужно
- Введите команды в текстовом редакторе
- Сохраните файл с расширением .ps1.
- Выполните файл в PowerShell
15) Для чего используется хеш-таблица в PowerShell?
16) Объясните, для чего используется массив в PowerShell?
17) Укажите, какую команду можно использовать для получения всех дочерних папок в определенной папке?
Чтобы получить все дочерние папки в определенной папке, вам необходимо использовать рекурсию параметров в коде. Get-ChildItem C:\Scripts –recurse
18) Объясните, как можно преобразовать объект в HTML?
Чтобы преобразовать объект в HTML Get-Process l Сортировка объекта – свойство ЦП – по убыванию l преобразовать в – HTML l Выходной файл «process.html»
19) Объясните, как можно переименовать переменную?
Чтобы переименовать переменную,
Rename-Item- Path Env: MyVariable –NewName MyRenamedVar
20) Объясните, какова функция входной переменной $?
Переменная $input позволяет функции получать доступ к данным, поступающим из конвейера.
21) По какому коду можно найти название установленного приложения на текущем компьютере?
Get-WmiObject-Class Win32_Product-ComputerName. l Формат широкого столбца1
22) Объясните, как в PowerShell можно найти все SQL сервисы находятся на одном сервере?
Есть два способа сделать это
- get-wmiobject win32_service l где-объект {$_.name-like «*sql*»}
- получить-сервис sql*
Эти вопросы для собеседования также помогут вам в устной речи.



