Powershell: How to reference the columns in a select - powershell

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

Related

Get-ADCompter command returns back null response

I'm trying to combine a string and an int together to get the output JWang1 but everytime I run this command it keeps returning back null, any help is appreciated, thank you
$pcname = "Jwang"
$number = 1
Get-ADcomputer -filter "name -like '$pcname + $number'" | select -ExpandProperty name
The goal is to get the command to search "JWANG1", but the result keeps coming back null
Alternatively if I do this, I get a search result posted back to me
$pcname = "Jwang1"
Get-ADcomputer -filter "name -like '$pcname'" | select -ExpandProperty name
The difference here is that I am not trying to combine the string and int, but how do I get it to combine and work?
The issue is how string expansion works, and how you're using it. Right now you have:
"name -like '$pcname + $number'"
Once you sub in the values for those variables it reads like this:
"name -like 'JWANG + 1'"
There's several ways you could go about correcting this. The first is to simply remove the + from the string so it reads like this:
"name -like '$pcname$number'"
The second way is to put in a subexpression like this:
"name -like '$($pcname + $number)'"
Or you could combine them before you reference it like:
$pcname = "Jwang"
$number = 1
$combinedname = $pcname + $number
Get-ADcomputer -filter "name -like '$combinedname'" | select -ExpandProperty name
In this case you would need to use the Subexpression operator $(..) to resolve the concatenation operation:
$pcname = "Jwang"
$number = 1
"name -like '$pcname + $number'"
# Interpolates both variables without resolving the concatenation
# Results in: name -like 'Jwang + 1'
"name -like '$($pcname + $number)'"
# Resolves the expression inside `$(..)` before interpolating it
# Results in: name -like 'Jwang1'
As aside, the right operator for your query to Active Directory should be -eq instead of -like since you're not using any wildcard for your query.

Foreach is not processing each item, tries to process all as one line

I am building a script to pull the mac addresses of a computer, and convert them to GUIDs that are then queried to AD to find a match and retrieve the hostname associate with that guid.
Everything I've read about "Foreach" suggests that the code I am using "SHOULD" work.
$NIC = Get-WMIObject Win32_NetworkAdapterConfiguration | select MacAddress
$NICMacs = $NIC.MacAddress
Foreach ($NICMac in $NICMacs)
{
$MacString = $NICMacs -replace ":", ""
$MactoGUID = "00000000000000000000" + $MacString
$MactoGUID = $MactoGUID -replace " ", ''
$NBG = [GUID]$MactoGUID
$CompDetails = Get-ADComputer -Filter 'netbootGUID -like $NBG' -Properties netBootGUID -Server our.AD.server.ca -Credential $sessionKey
This should process each mac address found, stripping away the: characters and prepending 20 '0s' then convert to GUID format and query AD for a match.
Instead, it takes all the mac addresses found, concatenates them to one line and tries to process with all those numbers. Of course AD rejects it as an incorrect GUID.
If I use the same code with only 1 mac address, it is correctly formatted.
Some of your steps can be combined and thus save intermediate vars using
Select-Object -ExpandProperty MacAddress
.PadLeft() method
As #RobV already pointed out in his comment usage of the wrong var caused the malfunction.
Foreach ($NICMac in (Get-WMIObject Win32_NetworkAdapterConfiguration |
Where-Object MacAddress -ne '' |
Select-Object -ExpandProperty MacAddress) ) {
$NBG = [GUID]($NICMac -replace ':').PadLeft(32,'0')
$CompDetails = Get-ADComputer -Filter 'netbootGUID -like $NBG' `
-Properties netBootGUID -Server our.AD.server.ca -Credential $sessionKey
}
I don't consider usage of a line continuation character esoteric,
here it allows keeping the overview.
I agree that Natural Line Continuations in PowerShell are preferable.
A couple items here:
In your code, in line 7, you reference $NICMacs, but you should be referencing $NICMac since the foreach is running through the logic separately, not as a batch.
You could simplify at least the top two lines into a single line without a pipe.
$NICMacs = (Get-WMIObject Win32_NetworkAdapterConfiguration).MacAddress
Foreach ($NICMac in $NICMacs)
{
$MacString = $NICMac -replace ":", ""
$MactoGUID = "00000000000000000000" + $MacString
[GUID]$NBG = $MactoGUID -replace " ", ''
$CompDetails = Get-ADComputer -Filter 'netbootGUID -like $NBG' -Properties netBootGUID -Server our.AD.server.ca -Credential $sessionKey
Edit: in my suggested code, I think making $NBG should work with the [GUID] tag in front but I've never tried it

How to remove characters from an item in an array using PowerShell

I have an array of computer names, $computers, that are in a FQDN format. I want to trim all characters to the right of the first period and including the period.
Ex: server-01.mydomain.int = server-01
This is what I tried but it errors out.
$computers = Get-VM | Select Name
$computers = $computers.Substring(0, $computers.IndexOf('.'))
$computers
When you do |Select Name, PowerShell returns an object with a Name property, rather than only the value of each Name property of the input objects.
You could change it to Select -ExpandProperty Name and then iterate over each item in the array for the actual substring operation using a loop or ForEach-Object - although we can skip the first step completely:
$computers = Get-VM |ForEach-Object { $_.Name.Substring(0, $_.Name.Indexof('.')) }
Or another way.
$computers = Get-VM | ForEach-Object { ($_.Name -split ".")[0] }
Since you are always selecting the first string before the first "." you can just split at the dot and select the first element in the resulting array.

How do I reference an object's property in a Powershell Active Directory cmdlet?

Related to this fantastic answer about how to properly construct a -Filter parameter argument, I'm working on a script that makes heavy use of the Active Directory cmdlets in PowerShell, and am having difficulty constructing filter arguments containing the property of an object variable.
The script basically manages distribution groups by reading in spreadsheet and processing each row as appropriate - creating Active Directory contacts if they don't exist, adding or removing them to the appropriate group and so on.
The spreadsheet is stored in an object array, with each row being treated as an object, with the columns defining the object properties.
For example, the below code takes each row of the imported spreadsheet and attempts to find a matching contact object in Active Directory.
Foreach ($contact in $NOClist)
{
$contactobject = Get-ADObject -filter ("name -eq `"$contact.name`" -and Objectclass -eq `"contact`"") -SearchBase "$NOCContactPath" -Server $ADServer;
#... do some more stuff.
}
The problem is that $contact.name is being evaluated literally, so it ends up searching for a contact in Active Directory with a name property that's literally $contact.name. I've tried the other variations in the previously referenced answer, (""$contact.name"", '$contact.name' and "' + $contact.name + '"), but they all either evaluate to the literal $contact.name or throw a syntax error on the . character.
The hacky workaround I've come up with is to assign the object property to a variable and use that instead, such as the below, but that just feels terrible.
Foreach ($contact in $NOClist)
{
$contactname = $contact.name;
$contactobject = Get-ADObject -filter ("name -eq `"$contactname`" -and Objectclass -eq `"contact`"") -SearchBase "$NOCContactPath" -Server $ADServer;
#... do some more stuff.
}
Is there a way to reference an object property inside the filter argument, or is this workaround of assigning it to a variable and then using the variable really the best approach?
PowerShell does only simple variable expansion in strings, no complex stuff like index or dot-property access. There are several ways to deal with this limitation, e.g.
concatenation:
-Filter ("name -eq '" + $contact.name + "' -and Objectclass -eq 'contact'")
subexpressions:
-Filter "name -eq '$($contact.name)' -and Objectclass -eq 'contact'"
the format operator:
-Filter ("name -eq '{0}' -and Objectclass -eq 'contact'" -f $contact.name)
Note that for the first and third approach you need to put the operation in a grouping expression (i.e. in parentheses), so that the result of that operation is passed to the parameter.
First, are you sure that $contact.name is valid within that that loop? For debug purposes, throw a write-host in there to make sure it's what you think it should be.
But the major thing is that you're using single-quotes around the variable, which blocks variable expansion. It looks like you're trying to escape the double-quotes, not sure if that's possible but if it is, that's not the right way to do it. You should be shooting for this from the link:
Get-ADUser -Filter ('sAMAccountName -eq "' + $SamAc + '"')
Example for me:
PS V:> $contactname = "finn2617"
PS V:> Get-ADuser -filter ('samaccountname -eq "' + $contactname + '"' ) | select name, samaccountname
name samaccountname
---- --------------
Finnigan, Matthew FINN2617
So, for you:
$contactobject = Get-ADObject -filter ('name -eq `"' + $contact.name + " -and Objectclass -eq "contact" ' ) -SearchBase "$NOCContactPath" -Server $ADServer;

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)