powershell how do I Create/format a dynamic list from a group membership to use in a for each loop - powershell

bit of a noob question.
I have the following cmd which grabs the server members of a group which I can copy into a text list. however as the group changes I need to modify the text list manually.
Get-AdGroupMember -identity "Reboot 7pm" | Sort-Object | select name
when I have that output in a text list, the following works fine.
$listpath = "C:\Scripts\servers.txt"
[System.Collections.ArrayList]$list = #(Get-content $listpath)
foreach($ComputerName in $list)
{
Get-Uptime -ComputerName $ComputerName
I want to know if it is possible to use a variable that I can use again in a for each loop. I've tried to do so, however the format of the list is not the same when is goes into a variable, thus the function (get-uptime) against the server doesn't work, anyone know what I can do to format the output so I only get the server name?
EG.
$WSUS_7PM = Get-AdGroupMember -identity "Reboot 7pm" | Sort-Object | select name
PS C:\Windows\system32> $WSUS_7PM
name
----
AXXXXX003
BXXXXX005
CXXXXX006
DXXXXX007
PS C:\Windows\system32> foreach($Name in $WSUS_7PM) {Write-Host $Name}
#{name=AXXXXX003}
#{name=BXXXXX005}
#{name=CXXXXX006}
#{name=DXXXXX007}
so when I run the same cmds as above modified with the variable instead of the text list, I get the following as the server name is obviously incorrect.
$listpath = $WSUS_7PM
[System.Collections.ArrayList]$list = #(Get-content $WSUS_7PM)
foreach($ComputerName in $list)
{
Get-Uptime -ComputerName $ComputerName
WARNING: Unable to connect to #{name=AXXXXX003}
WARNING: Unable to connect to #{name=BXXXXX005}
I hope that makes sense to someone, appreciate the help in understanding what the difference is in the object output.
Thanks
Alzoo

When you use Select-Object name you are creating a list of objects with a name property. You can either expand it ahead of time
$WSUS_7PM = Get-AdGroupMember -identity "Reboot 7pm" | Sort-Object | Select-Object -ExpandProperty name
or reference the name property later
foreach($Name in $WSUS_7PM.name) {Write-Host $Name}

Related

Multiple rows in a grid [duplicate]

This question already has answers here:
Export hashtable to CSV with the key as the column heading
(2 answers)
Closed 4 years ago.
I'm trying to list all ad group memberships of specific users. The input would be a string of logins split with a comma 'login1,login2'.
So I go over each user and list their memberships with the username as title. Somehow it only shows the first entry. Also it shows the user groups in one row and I don't know how to change that.
Code below:
$users = $logon -split ','
$q = #()
foreach ($user in $users) {
$usernm = Get-ADUser -Filter 'samAccountName -like $user' | select Name
$useraccess = Get-ADPrincipalGroupMembership $user | Select-Object Name
$userobj = New-Object PSObject
$userobj | Add-Member Noteproperty $usernm.Name $useraccess.Name
$q += $userobj
}
Expected output would be something like:
fullnameuser1 fullnameuser2 list of users goes on...
------------- ------------- ------------------------
adgroup1 adgroup3 ...
adgroup2 adgroup4
... ...
In principle this would also mean that if i typed $q.'fullnameuser1' output would be:
fullnameuser1
-------------
adgroup1
adgroup2
...
Whenever the code is ran, it will only ever add the first user's access, also returning all groups on one row. So somehow I need to go over all the group memberships and add a row for each one.
First and foremost, PowerShell does not expand variables in single-quoted strings. Because of that Get-ADUser will never find a match unless you have a user with the literal account name $user. Also, using the -like operator without wildcards produces the same results as the -eq operator. If you're looking for an exact match use the latter. You probably also need to add nested quotes.
Get-ADUser -Filter "samAccountName -eq '${user}'"
Correction: Get-ADUser seems to resolve variables in filter strings by itself. I verified and the statement
Get-ADUser -Filter 'samAccountName -eq $user'
does indeed return the user object for $user despite the string being in single quotes.
If you want a fuzzy match it's better to use ambiguous name resolution.
Get-ADUser -LDAPFilter "(anr=${user})"
You may also want to avoid appending to an array in a loop, and adding members to custom objects after creation. Both are slow operations. Collect the loop output in a variable, and specify the object properties directly upon object creation.
$q = foreach ($user in $users) {
...
New-Object -Type PSObject -Property {
$usernm.Name = $useraccess.Name
}
}
Lastly, I'd consider using the user's name as the property name bad design. That would be okay if you were building a hashtable (which is mapping unique keys to values), but for custom objects the property names should be identical for all objects of the same variety.
New-Object -Type PSObject -Property {
Name = $usernm.Name
Group = $useraccess.Name
}
Basily query all the users and store it in $users, example:
Get-ADUser -Filter * -SearchBase "dc=domain,dc=local"
And then you can export the results as csv or a table.
To Export as CSV :
Get-ADPrincipalGroupMembership <Username> | select name, groupcategory, groupscope | export-CSV C:\data\ADUserGroups.csv`
To Format the result as Table in the console itslef :
Get-ADPrincipalGroupMembership <Username> | select name, groupcategory, groupscope | Format-Table

Extracting part of a host name with select-object

I have a simple powershell function where I provide the log type and event and it scans all of our SQL servers. it works except the host name is returned as hostname.domain.local. I want it to return just the host name. I've tried machinename.split('.') and substring and it won't work. I've tried putting the select-object into a separate variable and was going to join it with the rest of the columns, but it takes too long to run.
Here is my sample scrap code i'm testing with before I change my function along with the commented out parts that didn't work. Looked around and found lots of resources about the commands, but they don't work when I try to use them in my script.
The error I keep getting is A positional parameter cannot be found that accepts argument '. '.
$servers = Get-Content -literalpath "C:\temp\sql_servers3.txt"
#$server
#$result =
ForEach($box in $servers) {Get-Eventlog -ComputerName $box -LogName
application -After 1-4-2018 -Entrytype Error | Where {$_.source -notin
'Perfnet','Perflib', 'ntfs', 'vss'}| select-object -property MachineName}
#$result_Host_name = select-object -inputobject $result -property
'MachineName'
#'TimeGenerated', 'MachineName'.Split('.')[1], 'EventID','message'}
#| Where {$_.source -notin 'Perfnet','Perflib', 'ntfs', 'vss'} 0
#return $result_Host_name
What you are looking for is a "Calculated Property" when using Select-Object.
| Select-Object #{n='HostName';e={($_.MachineName -split '\.')[0]}}

Remove #{ColumnName from Powershell results

I'm relatively new to PowerShell scripting and have mainly been cobbling together different scripts and cmdlets from Googling what I'm trying to do. One problem that I'm unable to Google, or search for on StackExchange, because of the special characters is having all my results come out as #{ColumnName=ColumnData}.
Here's an example script I found somewhere for pulling all the members of an AD group.
$Groups = Get-ADGroup -Filter {Name -like "!GroupName"}
$path = $groups
$myCol = #()
ForEach ($Group in $Groups)
{
$Members = #(Get-ADGroupMember "$Group")
ForEach ($Member in $Members){
try{
$user = get-aduser -identity $member -properties displayname
$MyObject = New-Object PSObject -Property #{
Displayname = $user.Displayname
}
$mycol += $MyObject}
catch {}}
}
Write-Host $MyCol | FL
I'm pretty sure there are better ways to get the members of an AD group but that's not the issue at the moment. The problem is all the data comes out like #{Displayname=Lawrence, Kimberly} and this happens with many of the scripts I've thrown together.
Any ideas on how to write scripts properly so I can just get DisplayName = Lawrence, Kimberly?
I agree your code is complex and it does not need to be. A couple of things that are important to mention is why your output looks the way it does.
You are creating an array of PSCustomObjects which function similar to hash-tables. In the end of your processing you have an array of objects with the property DisplayName. Since you are using Write-Host to display the the contents of $myCol it needs to cast it a string array in order to display it. You would see similar output if you just typed [string[]]$myCol. I should hope that you are doing something else in the processing as like the other answers show you have a very complicated way of getting what you are looking for.
Without beating the horse about those other solutions I will suggest some minor changes to yours as it stands. Your title and last sentence contradict what you are looking for since you want to remove the ColumnName in the title and the last sentence you are looking for output like DisplayName = Name.
Changing the last line will address both of these. If you just want the displaynames on there own
$myCols | Select-Object -ExpandProperty DisplayName
Lawrence, Kimberly
and if you actually want the other format you could do this
$myCols | ForEach-Object{
"DisplayName = $($_.DisplayName)"
}
Again, like the other answers, I stress that your code could use simple overhaul. If you needed to understand why it was working the way it way I hope I helped a little.
This actually has nothing to do with Active Directory; You are creating custom objects, then outputting them directly, and by default that is how PowerShell will format the output if you use Write-Host (which is intended to customize output). If you would like to be more specific about what your output should look like, we can help, but here is an example that outputs the results as just a list of strings, just using Write-Output:
$myCol = #()
$MyObject = New-Object PSObject -Property #{ DisplayName = "Lawrence, Kimberly" }
$myCol += $MyObject
$MyObject = New-Object PSObject -Property #{ DisplayName = "Hello, World" }
$myCol += $MyObject
# The default will show at-symbols, etc: Write-Host $MyCol | FL
Write-Output $myCol
The output will be:
DisplayName
-----------
Lawrence, Kimberly
Hello, World
Try this:
Get-ADGroup -Filter "Name -like '!GroupName'" |
Get-ADGroupMember |
Get-ADUser -Properties DisplayName |
Select-Object DisplayName
When I ran your code, I also got the hashes, even without special characters. Your code is way too unnecessarily complex.

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)

Powershell pipeline - Retrieve outputs from first cmdlet?

I am trying a few things in Powershell and what I don't manage to achieve is the following (in Exchange):
Get-User | Get-MailboxStatistics
But in the output I would like some fields/outputs from the "Get-User" cmdlet and some fields/outputs from the "Get-MailboxStatistics" cmdlet.
If anyone has an answer, I have searched the web but with no success as I've had difficulties explaining it in a few words.
Thanks in advance for your help.
Start with the execution of one cmdlet, pipe the results to Foreach-Object and then save a reference to the current object ($user), now execute the second command and save it in a variable as well. Create new object with properties from both objects.
You also need to filter users that have mailboxes, use the RecipientTypeDetails parameter.
$users = Get-User -RecipientTypeDetails UserMailox
$users | Foreach-Object{
$user = $_
$stats = Get-MailboxStatistics $user
New-Object -TypeName PSObject -Property #{
FirstName = $user.FirstName
LastName = $user.LastName
MailboxSize = $stats.TotalItemSize
ItemCount = $stats.ItemCount
}
}
I don't know if it is the best or optimal solution, but you certainly do it by saving actual user to variable in foreach:
$users = Get-User
$users | % { $user = $_; Get-MailboxStatistics $_ | %
{
"User name:{0} - some mailbox statistics: {1}" -f $user.SomePropertyOfUser, $_.SomePropertyOfMailbox
}
}
The first step (saving users into separate variable) is required only when working with Exchange cmdlets - as mentioned here, you cannot nest Exchange cmdlets in foreach...
This error is caused when executing the Exchange cmdlets through PowerShell remoting, which do not support more than one pipeline running at the same time. You may see this error when you pipe the output from a cmdlet to foreach-object, which then runs another cmdlet within its scriptblock.
$users = Get-User -RecipientTypeDetails UserMailbox
$users | Foreach-Object{ $user = $_; $stats = Get-MailboxStatistics $user.DistinguishedName; New-Object -TypeName PSObject -Property #{FirstName = $user.FirstName; LastName = $user.LastName;MailboxSize = $stats.TotalItemSize;ItemCount = $stats.ItemCount }}
I've had to add a specific field in input of Get-MailboxStatistics because remotely, I was having:
The following Error happen when opening the remote Runspace: System.Management.Automation.RemoteException: Cannot process argument transformation on parameter 'Identity'. Cannot convert the "gsx-ms.com/Users/userName1" value of type "Deserialized.Microsoft.Exchange.Data.Directory.Management.User" to type "Microsoft.Exchange.Configuration.Tasks.GeneralMailboxOrMailUserIdParameter".
Anyway, thank you both #Jumbo and #Shay-levy
Get-ADUser -identity ADACCOUNT | Select-object #{Name="Identity";Expression={$_.SamAccountName}} | Get-MailboxStatistics
For some reason the Identity parameter doesn't take pipelne input by value, only by property name. So in order to get it to work you can change the name of piped in data to match the parameter name of Identity. Then Get-MailboxStatistics finally knows how to treat the data your feeding it via the pipeline.