1

I have a large variety of computers and I am writing a Powershell script that mounts a network share with a local repository of computer drivers on my server that are saved in their own separate directories as the Make and Model of each machine (e.g. Lenovo E460, Dell Latitude E5450, etc.).

Here's what i'm trying to do:

I want the to get the computer's information (make and model) and concatinate it into a string. Then I'd like that string to then be referenced against an array of the driver directories and if the computer make + model matches, i'd like the computer to download the drivers inside of that directory. I am from a web development background, and here is where I'd usually use the JavaScript Array.prototype.filter() method to filter the array down to compare $computer to each child item in the $drivers array.

$computer = (gwmi Win32_ComputerSystem).Manufacturer + " " + (dwmi Win32_ComputerSystem).Model
$drivers = Get-ChildItem \\zapp\pc\!Drivers

What is the best way to accomplish this is Powershell? Does Powershell have filtering and comparison Array methods similar to JavaScript? Or would a Foreach -match or -eq be the most efficient way of writing it?

Thanks!

1
  • take a look at the .Where() collection method. [grin] Commented Feb 15, 2021 at 23:28

2 Answers 2

2

You should be able to accomplish this without an array or any (explicit) filtering.

Firstly, for efficiency's sake I would initialize $computer like this...

$computerSystem = gwmi Win32_ComputerSystem -Property 'Manufacturer', 'Model'
$computer = $ComputerSystem.Manufacturer + " " + $computerSystem.Model

If you want to get fancy you could also do...

$computer = $computerSystem.Manufacturer, $computerSystem.Model -join " "

Now, instead of managing and searching an array of driver directories yourself, you can let the filesystem do this for you...

$driverDirectory = Get-Item -LiteralPath "\\zapp\pc\!Drivers\$computer"

This will throw an error if no object exists at the specified path. You can combat that like this...

$driverDirectory = Get-Item -LiteralPath "\\zapp\pc\!Drivers\$computer" -ErrorAction SilentlyContinue
if ($null -ne $driverDirectory)
{
    # $driverDirectory exists; copy drivers
}

...or like this...

$driverDirectoryPath = "\\zapp\pc\!Drivers\$computer"
if (Test-Path -Path $driverDirectoryPath)
{
    # $driverDirectoryPath exists; copy drivers
}

The only real downside of doing it this way instead of what you proposed is that if !Drivers\ is a huge directory (i.e. thousands of children) and you're repeatedly looking up driver directories then that directory enumeration could be noticeably slower than caching the results yourself in an array. I'm guessing your script will only be copying the applicable drivers for the local system so, like I said, I'd just let the filesystem do what it does best.

Sign up to request clarification or add additional context in comments.

2 Comments

This is beautiful and exactly what I needed. Thank you. If I may ask, why did you intitialize the $computer and make/model variables the way you did? Why is that more efficient? Also, I have never run across -ne. I'm assuming in this context it means "not equal". Can you confirm?
Yes, -ne is the "not equal" operator. Any WMI operation tends to be slow, and in the original code you are performing two: one to retrieve a complete Win32_ComputerSystem object and get its Manufacturer property, and a second to retrieve another complete Win32_ComputerSystem object and get its Model property. In my code I only perform one such retrieval and then use that same object to get both properties. I also use the -Property parameter to specify only the properties I'll be accessing so it won't bother populating the others.
2

Hello and good evening.

Untill someone much smarter than me comes a long (which wont be long), I can try to point you in the right direction.

You actually have several options here. You can use conditional statements that rely on bools (booleans - just posh way of saying it), and Where-Object combined with some operators.

Let me first post this so it doesnt crash on me (Cracked my screen and its acting wonky). We'll start you off with the Switch Statement. Where if a condition is met, do something.

$computer = (gwmi Win32_ComputerSystem).Manufacturer + " " + (gwmi Win32_ComputerSystem).Model
$drivers = Get-ChildItem \\zapp\pc\!Drivers | Select-Object -ExpandProperty Name
    Switch ($drivers){
        "$computer" {"Found: $_" }
        
        }

I am back! So, back to where I left off... You can use the switch statement which will do something when a specific condition is met; in this case, its executing a copy-item from the remote PC onto the local one, once it detected what the string matched what you were looking for. See below:

$computer = (gwmi Win32_ComputerSystem).Manufacturer + " " + (gwmi Win32_ComputerSystem).Model
    Switch (Get-ChildItem \\zapp\pc\!Drivers){
        "$computer" {Copy-Item -Path $_.FullName -Destination C:\DriverStore }
            }

Using the Foreach loop, we can iterate through each file and attempt to match the the value you're passing it using an if statement, executing a Copy-Item on the remote PC onto yours once found.

Foreach($file in (Get-ChildItem \\zapp\pc\!Drivers)){
    if($file -match  $computer){ Copy-Item -Path $file.FullName -Destination C:\DriverStore}
        }

Next, we are just piping the files over to the Where-Object with the help of a -match operator, matching the value specified to it against the objects on the left. A Foreach-Object cmdlet (not to be confused with Foreach) is used at the end with a parameter of -Process to run each element inside the input object. Then copying over from the remote PC to yours the folder that matched your PC.

$computer = (gwmi Win32_ComputerSystem).Manufacturer + " " + (gwmi Win32_ComputerSystem).Model
Get-ChildItem \\zapp\pc\!Drivers | Where-Object {$_.Name -match $computer} |ForEach-Object -process{ Copy-Item -Path $_.fullname -Destination C:\DriverStore}

Hopefully, this makes sense and can get you on the right track. There are a couple of others I didnt mention just to keep it simple but, @Lee_Daily did mention the .Where() method which could be used in this situation as well.

2 Comments

I apologise, my computer bsod. Will fix it and finish this, too much to type on my phone.
Thank you for taking the time to write out this response! It's very well typed out and comprehensive. While I did not go with it as my final solution, I did learn some things. So thanks again.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.