Powershell Where-Object Match - powershell

I want to use the Where-Object to limit the Output of Get-PSDrive to only network shares.
Get-PSDrive shows me the following:
Name Used (GB) Free (GB) Provider Root CurrentLocation
---- --------- --------- -------- ---- ---------------
A FileSystem A:\
Alias Alias
C 16.19 43.47 FileSystem C:\ Users\HansB\Documents
Cert Certificate \
D FileSystem D:\
Env Environment
Function Function
HKCU Registry HKEY_CURRENT_USER
HKLM Registry HKEY_LOCAL_MACHINE
V 451.39 159.76 FileSystem \\192.168.71.31\fs_log_target
Variable Variable
W 197.72 FileSystem \\192.168.71.32\perf200
WSMan WSMan
X 197.72 FileSystem \\192.168.71.32\perf100
Y 271.52 34.33 FileSystem \\192.168.71.30\group200
Z 271.52 34.33 FileSystem \\192.168.71.30\group100
Then I want to get the \\192.168.71.30\group100 Network Share:
Get-PSDrive | Where-Object { $_.Root -match "\\\\192.168.71.30\\group100" }
But I get nothing, why does -match not work?

Use DisplayRoot instead of Root property
Get-PSDrive | Where-Object { $_.DisplayRoot -match "\\\\192.168.71.30\\group100" }
try to run
Get-PSDrive | Where-Object { $_.DisplayRoot -match "\\\\192.168.71.30\\group100" } | select *
Root will be your mapped drive letter, and DisplayRoot your UNC Path
EDIT: as a side note. For escaping regex use [regex]::Escape() method.
PS > [regex]::Escape("\\192.168.71.30\group100")
\\\\192\.168\.71\.30\\group100

Try using -eq instead:
Get-PSDrive | Where-Object {$_.Root -eq "\\192.168.71.30\group100"}

If yoy type Get-PSDrive | select root you will notice that for network drives it will print nothing. So there is something strange with network share roots.
Get-PSDrive | select root | %{write-host $_.Root.GetType()} will show that it's a system string, so not quite sure why it seems to be empty for network drives.

Related

How to remove mapped network drive when created with a random letter

I am creating a mapped network drive with a random letter like this:
$drive = Get-ChildItem function:[f-z]: -n | Where { !(Test-Path $_) } | select -First 1
$PsDrive = New-PSDrive -Name ($drive)[0] -PSProvider "FileSystem" -Root $somePath
This code works fine. I have a problem when want to remove the newly created mapped drive at the end of my script. How I do it:
$someEnv = Remove-PSDrive -Name $drive
The problem here is that $drive adds the colon after the name ':'. For example if $drive is called M, it will be "M:" and Remove-PsDrive fails.
Probably it will be removed automatically when the session is over, but I want to remove it explicitly.
Do you guys have an idea how I can remove this drive?
Thanks
You can remove the ':' from the $drive variable using Replace
$drive.Replace(':','')
So your code to remove the drive looks like this
$someEnv = Remove-PSDrive -Name $drive.Replace(':','')
here is another, somewhat different way to do it that uses just powershell. [grin]
what it does ...
creates a list of possible drive letters
in this case, it is just F thru Z.
== uses 'F'[0] to convert the letter string to a character
== uses the range operator to coerce the chars to ascii code numbers
== generates a range from those code numbers
== coerces the code numbers back to characters & stuffs them into an array
in PoSh7, you can make that array with 'F'..'Z'. [grin]
grabs the in-use drive letters
filters the candidate letters against the in-use letters
grabs the 1st remaining letter
sets a target root
in this case it is the temp dir.
creates a new PSDrive with that letter
shows the drive letter in use by that new PSDrive
gets a dir list of the 1st three items in that PSDrive
removes the PSDrive
shows the current filesystem PSDrives
the code ...
$CandidateDriveLetters = [char[]]('F'[0]..'Z'[0])
$InUseDriveLetters = (Get-PSDrive -PSProvider FileSystem).Name
$1stAvailableDL = ($CandidateDriveLetters |
Where-Object {
$_ -notin $InUseDriveLetters
})[0]
$TargetDriveRoot = $env:TEMP
$NewDrive = New-PSDrive -Name $1stAvailableDL -PSProvider FileSystem -Root $TargetDriveRoot
$NewDrive.Name
'=' * 30
Get-ChildItem -Path ('{0}:' -f $NewDrive.Name) |
Select-Object -First 3
'=' * 30
Remove-PSDrive -Name $NewDrive.Name
(Get-PSDrive -PSProvider FileSystem).Name
output ...
H
==============================
Directory: C:\Temp
Mode LastWriteTime Length Name
---- ------------- ------ ----
d----- 2020-04-21 6:39 PM 2ccdytd4
d----- 2020-04-21 6:39 PM 30u23uyw
d----- 2020-04-21 6:39 PM 55zoq3fj
==============================
C
D
E
F
G
R
S
Z

Sort Drives by Free Space in Powershell

I'm trying to sort my drives using Powershell by free space. The purpose of this utility is to re-distribute one disk that is almost full across all the disks that are not as full.
Currently, my powershell script looks like this:
# Retrieves drives from My Computer
$Drives = gdr -PSProvider FileSystem
# Iterates over all drives found
foreach($Drive in $Drives) {
$Drive | Sort-Object -Property Free
}
The output is this:
Name Used (GB) Free (GB) Provider Root CurrentLocation
---- --------- --------- -------- ---- ---------------
C 151.09 688.31 FileSystem C:\
D 0.05 15.67 FileSystem D:\
F 0.09 2.96 FileSystem F:\
G 0.05 16.43 FileSystem G:\
H 0.03 9.73 FileSystem H:\
I 2.42 65.94 FileSystem I:\
But I'm expecting something like the Free (GB) Column to be sorted ASC
Any clues?
The problem was that I sorting the individual drive and not the collection as pointed out by #johnrsharpe and #Lee_Dailey
This ended up solving my problem:
# Iterates over all drives found
$SortedDrives = $Drives | Sort-Object -Property Used -Descending
foreach ($Drive in $SortedDrives) {
Write-Output $Drive.Name
}

Why does my -match call include an invalid item when getting network drives?

When calling
Get-PsDrive | Select Name,Root
I can see the followng drives:
Name Root
---- ----
Alias
C C:\
Cert \
Env
Function
G \\company.com\EVP\Data\Gen...
HKCU HKEY_CURRENT_USER
HKLM HKEY_LOCAL_MACHINE
Variable
WSMan
X \\server\C$
Z \\server\C$
Great. Now I only want the network drives, ie drives where Root contains \\ and Provider is FileSystem.
So I tried
Get-PSDrive |
where {$_.Provider -match "FileSystem" -and $_.Root -match "\\"}
| Select -ExpandProperty Name
But this includes the C drive for some reason. How is that possible?
I also tried changing to
$_.Root -match "\\\"
But I get
parsing "\\" - Illegal \ at end of pattern.
and
$_.Root -match "\\\\"
returns nothing.
-match takes a regular expression (regex) on the right, and in regular expression language a backslash is an escape character, and the way to specify a backslash is to escape it with another one - i.e. \\ translates to a single backslash, which matches drives like C:\.
Your options are:
$_ -match '\\\\' # two escaped backslashes
$_ -match [regex]::Escape('\\') # it returns \\\\ but maybe clearer to a reader what's happening
$_.StartsWith('\\') # don't use a regex, use a .Net string method
Edit:
As I mentioned in my question, when trying to -match with '\\', I get no return value.
Run Get-PsDrive Z | Format-List -Property * and see something like:
Used : 89738715136
Free : 29716107264
CurrentLocation :
Name : Z
Provider : Microsoft.PowerShell.Core\FileSystem
Root : Z:\
Description :
MaximumSize :
Credential : System.Management.Automation.PSCredential
DisplayRoot : \\localhost\c$
and it shows that the property root is really the drive letter, and the UNC path is called DisplayRoot. I don't know why, but it looks like the output formatting system is showing the DisplayRoot value and presenting it as the Root value. But that's just happening at the final presentation step, you can't use it in your script.
#Lieven Keersmaekers' suggestion of using $_.DisplayRoot -match '\\\\' is good.

Get iscsi mapped drive letter from iscsi initiator name

In PowerShell I'm trying to get the drive letter that an ISCSI target is mapped to. I'm using the following to get the ISCSI initiator name.
Get-IscsiTarget | ? {$_.IsConnected -eq $True} | Select -ExpandProperty NodeAddress
I have tried using Get-Disk | Select * and Get-PSDrive | Select * but these cmdlets do not seem to have any fields that I can link a target to, to obtain its drive letter.
As long as you have one active partition (not including reserved) per ISCSI target, you can use the following to match an ISCSI address to its corresponding drive letter.
foreach ($disk in (Get-Disk | ?{$_.BusType -Eq "iSCSI"})){
$DriveLetter = ($disk | Get-Partition | ?{$_.Type -eq "Basic"}).DriveLetter
$ISCSI = $disk | Get-IscsiSession
[pscustomobject]#{
DiskNumber=$disk.Number;
DriveLetter=$DriveLetter;
InitiatorNodeAddress=$ISCSI.InitiatorNodeAddress;
InitiatorIP=$ISCSI.InitiatorPortalAddress;
Size=$disk.Size;
}
}
This will check all connected ISCSI disks and get their corresponding drive letter, then it will put all the information into a customer PowerShell object and return it.

Get a partition name with PowerShell

I have a flash drive which I formatted so that the volume label on the drive is "PHILIP".
I am using Get-PSDrive H -PSProvider FileSystem to determine if the drive is plugged in, however I would really like to determine if the drive is plugged in by the volume label, i.e. Get-PSDrive -VolumeLabel PHILIP -PSProvider FileSystem. Of course the VolumeLabel parameter does not exist so this doesn't work.
Is there a way to list the drives in a computer by volume name?
You can use WMI, I guess:
Get-WMIObject Win32_Volume | ? { $_.Label -eq 'PHILIP' }
You can use the DriveInfo class from the .NET framework as well:
PS> [System.IO.DriveInfo]::GetDrives()
Name : C:\
DriveType : Fixed
DriveFormat : NTFS
IsReady : True
AvailableFreeSpace : 217269202944
TotalFreeSpace : 217269202944
TotalSize : 320070479872
RootDirectory : C:\
VolumeLabel : OS
You can then pipe that to the Where-Object cmdlet (both ? and Where are aliases) to filter that to just the volume you are looking for:
PS> [System.IO.DriveInfo]::GetDrives() | ? {$_.VolumeLabel -eq "PHILIP" }
I use Get-WMIObject like Joey proposes.
To link the wmi results to for example a get-partition i use the caption parameter.
In this example I set the partition letter of volume Philip to D
$datavolume=Get-WMIObject Win32_Volume | ? { $_.Label -eq 'PHILIP' }
$datavolume=$datavolume.Caption
get-partition -DiskNumber 0 | where {$_.accesspaths -like "$datavolume"} | Set-Partition -NewDriveLetter D