How to remove characters from an item in an array using PowerShell - 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.

Related

Powershell to list free domain computers

I'm using PowerShell to get a lit of all our domain computers, and then look for ones that are skipped, so we can easily get free computer names within this name range.
For example:
Get-ADComputer -Filter {Name -like "PC016*"} | Sort-Object | select Name
This gets me all our PCs starting with "PC016", and it works. From here I want to list all the skipped names.
For example, if I have this output:
PC016225
PC016226
PC016228
PC016229
I want Powershell to list the skipped item (PC016227).
How can I do this?
Remove the prefix from the names so you're left with the numerical suffix (eg. 225), then sort the resulting values to easily locate the lowest and highest values, and then simply output any number in between that isn't in the original list:
# Define computer name prefix
$prefix = "PC016"
# Create regex pattern for the prefix + a pattern to match only computer names ending with numbers
$prefixPattern = "^$([regex]::Escape($prefix))"
$namePattern = "${prefixPattern}\d+$"
# Query the directory for computer objects with the given naming prefix,
# filter the result so we only store computers with a numerical suffix
$computerNames = Get-ADComputer -Filter "Name -like '${prefix}*'" |Where-Object Name -match $namePattern |ForEach-Object Name
# Extract the numerical suffix and convert to a numeric type
$values = #($computerNames -replace $prefixPattern) -as [int[]]
# Sort the values
$values = $values |Sort-Object
# Now generate the range of values from the smallest to the biggest,
# filter out any values that are already found in the existing list
$skipped = $values[0]..$values[-1] |Where-Object { $_ -notin $values }
# ... and finally attach the prefix again and output the new possible names
$skipped |ForEach-Object { -join $prefix,$_ }

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 using where-object

I am using Powershell and am having trouble with the Where-Object cmdlet. I currently select * and then want to only output when a field is equal to Alabama. This field could be under any column, not just one.
This is what I have:
select * | where {$_.state_name -eq 'Alabama'} .
This works for state_name, but i cant get all columns without doing them individually. I've tried where{$_ -eq....} but that doesn't work.
Kind of a hack, but:
select * | where {($_ | ConvertTo-Csv -NoTypeInformation)[1] -like '*"Alabama"*'}
You have to iterate over all object's properties and check if it contains word 'Alabama'.
Example:
# Import CSV file and feed it to the pipeline
Import-Csv -Path .\My.csv |
# For each object
ForEach-Object {
# Psobject.Properties returns all object properties
# (Psobject.Properties).Value returns only properties' values
# -contains operator checks if array of values contains exact string 'Alabama'
# You can also use -like operator with wildcards, i.e. -like '*labama'
if(($_.PSObject.Properties).Value -contains 'Alabama')
{
# If any of the object properties contain word 'Alabama',
# write it to the pipeline, else do nothing.
$_
}
}

Format-Table not displaying a columns data

I am using the powershell command below to read a csv file and match the computer name to the employee name where the last login date is 181 days old. For some reason the Employee_Name column in the output is only displaying {} on each row. Any idea why its not returning the employee name?
Import-Module ActiveDirectory
$Days = (Get-Date).AddDays(-181)
$Computers = #{}
Import-CSV -Path c:\PS\ComputerNames.CSV | % { $Computers[$_.Computer_Name] = $_.Employee_Name }
Get-ADComputer -Property Name,lastLogonDate -Filter {lastLogonDate -lt $Days} -Server servername -Searchbase "OU=US,DC=Domain,DC=net" | ? { $Computers.Keys -contains $_.Computer_Name } | select Name,lastLogonDate,#{n='Employee_Name';e={$Computers[$_.Computer_Name]}} | ft
When you are looking at it in the debugger have you tried piping that field to Get-Member? I suspect that it is the array that Format-Table is not expanding but the debugger is able to unwind when you mouse over it. You are defining $Computers as an array. Maybe you only care about the first element in the array and you can define 'Employee_Name' as the first element of the array instead of the full array (of maybe just one element).

How to skip empty cells in a csv when using PowerShell to import Email Addresses?

I am trying to run the following script to import email addresses in powershell:
Import-CSV "C:\AliasesTest.csv" | foreach-object {
Set-Mailbox -Display Name $_.Name -EmailAddresses #{add=$_.Alias1,$_.Alias2,$_Alias3}}
It works fine, unless the csv has an empty cell under one of the Alias columns, at which point the following error is produced:
"The address '' is invalid: "" isn't a valid SMTP address..:
How can I construct my script to just ignore empty cells when it comes across them?
Check each property (alias) to see if it is empty, and only add the ones with values to the array inside your hash table:
Import-CSV "c:\AliasesTest.csv" | ForEach-Object {
#Save the CSV row for use in another loop later
$CSV = $_
Set-Mailbox -DisplayName $_.Name -EmailAddresses #{add = ("Alias1","Alias2","Alias3" | ForEach-Object { $Csv.$_ } | Where-Object{$_}) }
}
What that craziness does is, create a new hashtable with a key "add" that has a value of a sub expression. The sub expression has an array of property names that you want to check that it iterates over, converting each name to the value of that property, then filters out the empty ones.
Use a Where-Object filter prior to ForEach-Object like this:
Import-CSV "C:\AliasesTest.csv" | Where-Object {
$_.Alias1 -and $_.Alias2 -and $_Alias3
} | foreach-object { $_ }
If the alias' are empty strings they will be skipped. You don't have to use -and for all of them, if just one value is fine change to use -or.
Filter the aliases to take out the empty ones:
Import-CSV "C:\AliasesTest.csv" | foreach-object {
$aliases = #($_.Alias1,$_.Alias2,$_Alias3) | where-object{$_};
Set-Mailbox -Display Name $_.Name -EmailAddresses #{add=$aliases}}