List of drives as string array - powershell

I am working with a third party power-shell library. One of the function parameter in that library method is string array. This parameter value needs to contains the hard-disk drives. I have following script to retrieve the drives
[string[]] $drives = $null;
gwmi win32_logicaldisk -filter "drivetype = 3" | Select Name | % { $drives += $_.Name }
$drives -is [array]
Write-Output $drives
The output of this script is
True
C:
D:
However third party library doesn’t seem to accept this as an array. If I hard code the drives as follows, then everything works.
$drives = #('C:', 'D:')
My question is that the way I am retrieving drives as form of string array is correct? Note that I need to work against Power-Shell 2.0

Get-WMIObject is returning a collection of ManagementObject objects, and your Select-object is selecting one property of them for display. IOW, you're already getting an array (do your foreach-object in the pipeline isn't necessary), you just need the right kind of array (a string, in this case).
If you pass the -expandproperty parameter to select-object, you'll get an array of strings (in this case) suitable for your needs.
$drives = get-wmiobject win32_logicaldisk -filter "drivetype=3" | select-object -expandproperty name
write-output $drives
The output of your script as seen by the third-party library includes the output of $drives -is [array] (even though you don't explicitly use it in your script as shown here, write-output is implied), which is also causing it some consternation. Output that to a different stream ( like Write-Verbose or write-debug), or omit it altogether.

Related

Powershell: How to reference the columns in a select

I'm using PowerShell 5.1 to iterate through a list of computers from active directory, and I'm struggling with something that should be simple.
In the code below, I'm selecting the name and description for each computer in a foreach loop. How should I reference the name and description individually inside the loop?
$OU=#('OU=...')
$computers = $OU | foreach {Get-ADComputer -filter {
Name -notlike 'xxx*'
-and Name -notlike 'yyy*'
} -searchbase $_ -Properties description | Select name, description }
foreach ($computer in $computers) {
$computerName = $computer | select -ExpandProperty name
$computerDescription = $computer | select -ExpandProperty description
Write-Host "Host: $computerName [$computerDescription]"
}
I was able to get it to work using select -ExpandProperty , but this seems unnecessarily complicated. The $computer variable holds key/value pairs like this:
#{name=ABCDE12345; description=Kiosk PC [Domain Separated]}
I tried using dot notation $computer.name $computer.description but the dot was ignored and treated as text.
I have tried googling this, but I'm new to PowerShell and not sure how to phrase my question!
I tried using dot notation $computer.name $computer.description but the dot was ignored and treated as text.
String expansion only applies to simple variable references. If you want to dereference properties inside a string expression, you'll need the subexpression operator $():
"Host: $($computer.name) [$($computer.description)]"
PowerShell will now evaluate the subexpressions separately when resolving the string value

PowerShell script: AD query based on computer-name pattern not returning results [duplicate]

This question already has answers here:
Get-Aduser -Filter will not accept a variable
(8 answers)
Closed 4 years ago.
I am trying to create a PowerShell script that takes a list from an array of partial machine names and return them to me
So far, I've imported ActiveDirectory module and setup the array. I then run a foreach against the array but it doesn't return any results, instead going to a new line.
I have tried assigning the Get-ADComputer line to a variable and calling the variable. I have also tried to use the Return and not achieved my results.
The results can just print out in a list on the screen, that's OK. I just need it to return the results and then I can build up from that.
This is what I have done so far:
$getPC = #("7477", "7473", "7474")
foreach ($i in $getPC)
{
Get-ADComputer -filter {name -like "*$i*"} | select name
}
When I run the Get-ADComputer line alone, and put in the positional parameter, I have no problems. Any ideas?
Even though the practice is widespread, do not use script blocks ({ ... }) as the -Filter argument.
Construct your -Filter as a string, which is the -Filter parameter's actual type; you'll avoid many obscure problems if you construct it as such.
So, instead of:
-Filter { Name -like "*$i*" } # WRONG - do not use { ... }
use:
-Filter "Name -like '*$_*'" # OK - use of a string
For an explanation, see this answer of mine.
As an aside, you could simplify your command somewhat using a single pipeline with the ForEach-Object cmdlet, in whose script block the automatic $_ variable (alias name: $PSItem) represents the input object at hand:
"7477", "7473", "7474" |
ForEach-Object { Get-ADComputer -Filter "Name -like '*$_*'"} |
Select-Object Name
Regarding your original command: As Seth recommends, it's better to use a more descriptive loop variable name than $i, such as $computer.

Powershell - how to replace OS Version number with String

I am querying remote servers for their operating system. I know that I can return the Version, but I want to replace these values with the friendly name. The code I have so far is:
$Computer = (gc c:\servers.txt)
$BuildVersion = Get-WmiObject -Class Win32_OperatingSystem -Property Version, CSName -ComputerName $Computer -ErrorAction SilentlyContinue
$Build=$BuildVersion.version
If ({$BuildVersion.Version -match "5.2.3790"})
{$Build="2003"}
Elseif ({$BuildVersion.Version -match "6.1.7601"})
{$Build="2008"}
Elseif ({$BuildVersion.Version -like "6.3.9600"})
{$Build="2012"}
But this doesn't seem to work and only returns "2003" regardless. Please help, I'm fairly new to PS and coding.
thanks
The problem is your if statements. Putting the Boolean expression inside squiggly brackets makes it a script block, and that's going to get cast as a string before being cast as a Boolean. Strings cast to Booleans always evaluate to true unless they're empty.
PS C:\> {$BuildVersion.Version -match "5.2.3790"}
$BuildVersion.Version -match "5.2.3790"
PS C:\> ({$BuildVersion.Version -match "5.2.3790"}) -as [bool]
True
PS C:\> $BuildVersion.Version -match "5.2.3790"
False
PS C:\> ($BuildVersion.Version -match "5.2.3790") -as [bool]
False
So what you're running is essentially:
if ([bool]'$BuildVersion.Version -match "5.2.3790"') [...]
And that's always going to be true.
Try:
$Computer = (gc c:\servers.txt)
$BuildVersion = Get-WmiObject -Class Win32_OperatingSystem -Property Version, CSName -ComputerName $Computer -ErrorAction SilentlyContinue
$Build=$BuildVersion.version
If ($BuildVersion.Version -match "5.2.3790")
{
$Build = "2003"
}
Elseif ($BuildVersion.Version -match "6.1.7601")
{
$Build = "2008"
}
Elseif ($BuildVersion.Version -like "6.3.9600")
{
$Build = "2012"
}
Bottom line is that squiggly brackets are not parentheses and you can't use them like they are.
However, there's also a major logic error here. You're potentially fetching an array for $BuildVersion because you're reading from a file, but then you treat it like a single value. You never loop through $BuildVersion. However, I do not have enough information about what you're actually trying to do with your script (like what you do with $Build) to be able to fix that.
I originally said this, but I've since changed my mind
The reason this is only returning 2003 is that you're only running your If code on a single entry in the list.
Wrong
As TessellatingHeckler says, the reason your if wasn't working is that you had too many curly braces, so PowerShell wasn't actually evaluating your logic.
However, you still need to step through each of the computers to do what you're trying to do. We'll do that by adding in a ForEach loop. I also went ahead and replaced your If {} logic with a Switch statement, which I think is easier to understand for a scenario like this with multiple clauses. If's just get way too verbose.
Finally, I'm assuming you want to output the results too, so I added a custom object here, which is just a way of choosing which properties we want to display.
$Computer = (gc c:\servers.txt)
ForEach ($system in $computer){
$BuildVersion = Get-WmiObject -Class Win32_OperatingSystem -Property Version, CSName -ComputerName $system -ErrorAction SilentlyContinue
$Build=$BuildVersion.version
switch ($build){
"5.2.3790" {$Build="2003"}
"6.1.7601" {$Build="2008"}
"6.3.9600" {$Build="2012"}
}
#output results
[pscustomobject]#{Server=$system;OSVersion=$build;CSName=$buildVersion.CSname}
}#EndOfForEach
Output
>Server OSVersion CSName
------ --------- ------
dc2012 2012 DC2012
sccm1511 2012 SCCM1511
You can use this:
Get-WmiObject -Class Win32_OperatingSystem | Select-Object -ExpandProperty Caption
Additionally you can see everything this WMI object holds like this:
Get-WmiObject -Class Win32_OperatingSystem | fl *
Edit: if you want to remove some text from the string, you can use -replace:
(Get-WmiObject -Class Win32_OperatingSystem |
Select-Object -ExpandProperty Caption) -replace "Microsoft Windows Server ",""

powershell how to remove `{}#` from output. Is there a special command to do it?

I entered gwmi win32_product | select -property name | select -first 1 and output to a file. My result was #{name=Google Talk Plugin}.
How can I get rid of #{}, and name. I only want it to show Google Talk Plugin?
#{} means your exporting an object with properties. Try the -ExpandProperty parameter in Select-Object. You could also combine both select-object commands, like:
gwmi win32_product | select -expandproperty name -first 1
I ran into a problem similar with
$drive = Get-WmiObject Win32_LogicalDisk -ComputerName $servername | Select-Object DeviceID
$drive comes up as #{DeviceID=C:}, #{DeviceID=D:}, ...
Here is my brute force hack at it.
The second Trim statement was because for some reason if I put it in the first Trim it starts to Trim the letters in the Drive =D: becomes :
enter code here
$Asdrive = #() #declared before to get rid of null pointer issue, also to tell PS this is an array not a string
#Write-Host "Trimming for Get-WmiObject"
for($i=0;$i -lt $drive.length; $i++) {
[string]$sdrive = $drive[$i]
[string]$sdrive1 = $sdrive.Trim("#","{","}","D","e","v","i","c","e","I","D")
[string]$sdrive2 = $sdrive1.Trim("=")
$Asdrive += $sdrive2
}
If you're running at least Version 3, you can also use the member enumeration feature and then array slicing to take the first one, instead of using select:
(gwmi win32_product).name[0]
I add some code as I found this question with google.
Frode F. solution is the best one.
If you write out something like:
Get-ADComputer -Filter * -SearchBase $OU | Select-Object Name
you get a proper List of all Computers in an OU. You can also pipe that to a CVS/HTML file and its still nice.
| Export-CSV "mylist.csv"
But if you store it into a variable (array) every name will be wrapped in #{}.
In my case I needed computer names in a variable. Here is the solution thanks to Frodo:
$computerList = Get-ADComputer -Filter * -SearchBase $OU | Select-Object -ExpandProperty Name
Hope it helps someone.
(would add it as comment under the right solution, but I don't have enough reputation to do so)

-join operator on a variable for a parameter

function Get-Diskinfo {
param(
[string[]] $Computername = 'XEUTS001',
[string[]] $drive = 'c:'
)
$a = "-join $Computername[1..3]"
Get-WmiObject Win32_LogicalDisk `
-Filter "DeviceID = '$drive'" `
-ComputerName $Computername `
-Credential (Get-Credential -Credential ayan-$a) |
Select-Object `
#{n='Size'; e={$_.size / 1gb -as [int]}},
#{n='free';e={$_.freespace / 1gb -as [int]}},
#{n='% free';e={$_.freespace / $_.size *100 -as [int]}} |
Format-Table -AutoSize
}
I wrote this function to get some details about specific disks. However, I have to run them remotely and in a multi-domain environment. We have different usernames for computers in different OU's. I wanted the script to be able to take the username from the computername itself. The usernames are in this format ---- "name"+ "first 3 letters of the computername" which is the OU name. I am able to get the -Join method to work normally. However, it doesn't work if the variable is a parameter in a function. Here the username shows up as "ayan--join xeuts001[1..3]" when I want it to show up as "ayan-xeu"
What you have there is just a string that happens to contain a variable (which is expanded). Inside a string you are not in expression mode, so you cannot use operators. They just get embedded string content like you see there. What you want is probably:
$a = -join $Computername[1..3]
But that isn't correct, as it will yield oob for a computer name Foobar. If you want the first three letters, you'd need
$a = -join $Computername[0..2]
or even simpler (and easier to read, and faster):
$a = $Computername.Substring(0, 3)
P.S.: I also took the liberty of reformatting your original code, it was a horrible mess to read.