1

I want to have a script that copies a file from a USB drive to the system drive (most likely the C: drive). I need it to get a list of the drives that are of type USB. Then I need to check which of those drives has the folder containing the files I want to copy.

This is where I am currently at:

# find usb drive letters
        $usb = gwmi win32_diskdrive | ?{$_.interfacetype -eq "USB"} | %{gwmi -Query "ASSOCIATORS OF {Win32_DiskDrive.DeviceID=`"$($_.DeviceID.replace('\','\\'))`"} WHERE AssocClass = Win32_DiskDriveToDiskPartition"} |  %{gwmi -Query "ASSOCIATORS OF {Win32_DiskPartition.DeviceID=`"$($_.DeviceID)`"} WHERE 
        AssocClass = Win32_LogicalDiskToPartition"} | %{$_.deviceid}

if (test-path $usb[1]`:\DesiredFolder\file2copy.txt) {
        Copy-Item "$usb[1]`:\DesiredFolder\*" -Destination "C:\NewFolder"
}

Here is the response I get when outputting the $usb variable

F: D:

I know it is drive D on this computer, but I want the code to assume the drive letter is unknown so I don't have to worry about knowing which drive letter the USB is on other computers (even if there are multiple USB's plugged in).

How do I access the each drive letter individually to run a search for the folder that contains the files to be copied? Would I run a foreach on the $usb variable?

[Also, if you have any better advice on searching for the file, I'm open to anyone's advice. I was just going to run if (test-path $usb[1]`:\DesiredFolder\file2copy.txt){do stuff} but this is my issue, is the return from gwmi is not an array so I can't index the return value (aka drive letter) that I need to test the path (i.e. $usb[1] does not equal F:). I assume I need to split the results somehow, but when I tried the split function using ":" as delimiter, it gave an error (I assume because split is for strings, and the return from gwmi is some type of object)]

  • As an aside: The CIM cmdlets (e.g., `Get-CimInstance`) superseded the WMI cmdlets (e.g., `Get-WmiObject` (`gwmi`)) in PowerShell v3 (released in September 2012). Therefore, the WMI cmdlets should be avoided, not least because PowerShell (Core) (v6+), where all future effort will go, doesn't even _have_ them anymore. Note that WMI still _underlies_ the CIM cmdlets, however. For more information, see [this answer](https://stackoverflow.com/a/54508009/45375). – mklement0 Oct 20 '21 at 03:19

1 Answers1

0

Use ForEach-Object statement to loop over what $usb contains, which will enumerate its elements if it happens to be an array or use it as-is if it is a scalar (single value) - or take no action at all if $usb contains $null:

$usb | ForEach-Object {
  if (test-path ${_}:\DesiredFolder\file2copy.txt) {
    Copy-Item "${_}:\DesiredFolder\*" -Destination "C:\NewFolder"
  }
}

Note how the automatic $_ variable is represented with its name enclosed in {...} (i.e., ${_}) so as to disambiguate it from the : that follows (to prevent the : from being interpreted as a variable's scope specifier / namespace).
This technique is the more robust alternative to escaping the subsequent character with ` (which is what you attempted), as doing so could result in an inadvertent escape sequence.

mklement0
  • 382,024
  • 64
  • 607
  • 775