Есть простой способ удаления элементов из списка в powershell

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:

Find Duplicates in an Array in PowerShell

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
$duplicates

This 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:

PowerShell Find Duplicates in an Array

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.

Compare Two Arrays for Matches in PowerShell

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:

How to Compare Two Arrays for Matches in PowerShell

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.

PowerShell to Install Apps on Endpoints
Figure 1: Error when Import Microsoft Graph PowerShell Modules in Windows PowerShell 5

Есть простой способ удаления элементов из списка в powershell

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).
:/>  Схемы компьютерных блоков питания ATX, AT и ноутбуков

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-GridView

The result looks like the output shown in Figure 2.

PowerShell to Install Apps on Endpoints
Figure 2: Sample Result for the PowerShell script for device app list.

Let me explain the script flow:

  1. We define an empty array called tmp to store the result.
  2. Use Get-MgDeviceManagementDetectedApp -All to get all the detected app from Intune.
  3. 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.
  4. Inside the foreach loop, the script selects the required properties from the result and constructs a custom object.
  5. The script then uses Sort-Object to sort the output according to your needs.
  6. 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.

PowerShell to Install Apps on Endpoints
Figure 3: Result of Get-MgDeviceAppManagementManagedAppRegistration -All

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.

Using PowerShell to Get a Report of Installed Apps
Figure 4: Highlighted field showing .NET type name instead of actual data.

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
Using PowerShell to Get a Report of Installed Apps
Figure 5: Example Output of adding User’s DisplayName to Get-MgDeviceAppManagementManagedAppRegistration result.
  1. Gets the licensed user list from Get-MgUsers and stores in variable.
  2. Gets the Intune MAM registration information using Get-MgDeviceAppManagementManagedAppRegistration and stores in variable.
  3. 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.
  4. Displays the result in Out-GridView

Есть простой способ удаления элементов из списка в powershell

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.

About the Author

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:.

  1. Extended Functionality: Access features in .NET not available natively in PowerShell.
  2. 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
403031942000

PowerShell 7.4.1 uses .NET Core 8.0.1

 C:\> PSVersionToString
741 C:\> ::VersionToString
801

We 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
::IsNullOrWhiteSpace
IsNullOrEmpty
True
True
False
False
IsNullOrWhiteSpace
True
True
True
False

String 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 : 10111

However, 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 : 10001

However, we can get around this by comparing the input against the IPAddressToString output:

 IPAddressToString

Here 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
34ED1BAABBCC

Invalid 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 : FormatException

Compatibility 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
34ED1BAABBCC

These changes are documented in the Microsoft documentation.

parse remarks

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:\> Dispose

It 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.

:/>  Winsat exe что это

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+dNU

Let’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:

 = ::New

The second is to place a using statement at the top of the script, and then reference the type only by its name.

 namespace SystemCollectionsGeneric = ::New

We 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
Add20

Now 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 format

List Caveats

 = ::New
Add
Add
Add30

Here the integer 30 was automatically cast to the string "30".

 C:\>
ten
twenty
30 C:\> 2GetType
IsPublic IsSerial Name BaseType
True True String SystemObject

This appears to be a PowerShell specific behaviour as the equivalent C# code will throw an exception.

 Numbers
Numbers
Numbers
Numbers
Error 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
1

Setting 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.

Microsoft documentation showing Parse as a static method

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.

List class documentation

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 different

There 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
51395

As 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 : 045215

In 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 IBinaryIntegerGetShortestBitLength

We 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
Find

If 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
First

Using 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`1

We 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 IDeserializationCallback

PowerShell 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 IStructuralEquatable

Let’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
True

Let’s check PowerShell arrays.

 C:\> = C:\> = C:\> IsAssignableFrom
False

We 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=

 namespace SystemCollectionsGeneric = ::New \trustedtxt = ::New \accesslogtxt

Here are the contents of those two files:

102501100
102501101
192168150
102501120
102501100
215714595
102501100
102501100
102501100
125286035
125286035

We 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
125286035

Now let’s use LINQ to extract the logged IPs but exclude our trusted addresses.

 C:\> = ::Except C:\> Expand IPAddressToString
192168150
102501120
215714595
125286035

That 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
# 10

System.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
# 10

Note 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

Вопросы для собеседования по 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 используется для объединения двух операторов, при котором выходные данные одного оператора становятся входными данными второго.

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*

Эти вопросы для собеседования также помогут вам в устной речи.