Break csv data based on server name - powershell

I am having below data in my csv file
"Server Name","Control Group","Tape Number","Status"
"BR502","QCLDUSYSW","Q23028","ACTIVE"
"BR502","QCLDUSYSW","Q32521","ACTIVE"
"BR502","QCLDUSYSW","Q05599","ACTIVE"
"BR503","QCLDUIPLW","Q25582","ACTIVE"
"BR503","QCLDUIPLW","Q15529","ACTIVE"
"BR503","QCLDUIPLW","Q05109","ACTIVE"
"BR504","QCLDUSYSW","Q14445","ACTIVE"
"BR504","QCLDUSYSW","Q27785","ACTIVE"
"BR504","QCLDUUSRD","Q26071","ACTIVE"
"BR505","QCLDUGRPD","Q27657","ACTIVE"
"BR505","QCLDUIPLW","Q17404","ACTIVE"
Please let me know how to break it based on server name like below
"Server Name","Control Group","Tape Number","Status"
"BR502","QCLDUSYSW","Q23028","ACTIVE"
"BR502","QCLDUSYSW","Q32521","ACTIVE"
"BR502","QCLDUSYSW","Q05599","ACTIVE"
"Server Name","Control Group","Tape Number","Status"
"BR503","QCLDUIPLW","Q25582","ACTIVE"
"BR503","QCLDUIPLW","Q15529","ACTIVE"
"BR503","QCLDUIPLW","Q05109","ACTIVE"
so on for rest of the servers.

Use the Group-Object cmdlet to group the records together based on a particular property:
Import-Csv .\input.csv |Group-Object -Property 'Server Name' |ForEach-Object {
# for each group, output a new CSV file with just the records pertaining to that server, named after the server
$_.Group |Export-Csv .\$($_.Name).csv -NoTypeInformation
}

Something like this might do what you want:
import-csv tst.csv | where 'Server Name' -eq 'BR502'
If you want to examine each set you would use a Group-Object to bunch it on Server Name like this:
Import-Csv tst.csv | Group-Object 'Server Name'
This gives an object that has two properties Name, Count and Group which contain the Value you groped by, the number of items in the group and the list of items in the group. This can be used for calculations on each group. For example if you want to know how many in Control Groups in each server end with D you could use this:
Import-Csv tst.csv | Group-Object 'Server Name' | Foreach-Object { $name=$_.Name; Write-Output $_.Group | Where-Object 'Control Group' -LIKE '*D' | Measure-Object | Select-Object #{Label='Name';Expression={$name}},Count }
If you use aliases that command can be shortened to:
ipcsv tst.csv | Group 'Server Name' | % { $name=$_.Name; $_.Group | ? 'Control Group' -LIKE '*D' | Measure | Select #{L='Name';E={$name}},Count }

Related

Powershell print sub-level objects in FT

I have the following generic structure:
Powershell command returns an object containing named fields and values. Some of those values are objects with another struct of names and values below them.
I want to simply print the results in a FL, but I want the sub-object values included.
The following code provides me the output I'm looking for, but I feel like I'm not doing this in a powershell-efficient way and I should be able to pipe this into a one-liner
foreach ($user in (Get-MsolUser | ?{$_.StrongAuthenticationmethods -ne $null})){
Write-host "$($user.UserPrincipalName) :: $($user.DisplayName)"
foreach($method in $user.StrongAuthenticationMethods){
write-host "`t$($method.MethodType)"
}}
I was hoping the above could be shortened to resemble the below non-functional code... is something like this possible to dump the property values when there could be a number of results between 0-X (max 4 in my case)?
Get-msolUser|?{$_.StrongAuthenticationmethods -ne $null} | select UserPrincipalName,Displayname,isLicensed,(StrongAuthenticationmethods | fl)
Use a calculated property:
Get-MsolUser |
Where-Object { $null -ne $_.StrongAuthenticationmethods } |
Select-Object UserPrincipalName, Displayname, isLicensed, #{
Name='StrongAuthenticationmethods'
Expression={ $_.StrongAuthenticationmethods.MethodType -join "`n" }
} |
Format-List
The above uses Format-List (fl), but if you prefer a tabular representation via Format-Table (ft) instead, replace | Format-List with | Format-Table -Wrap.

How to look for Active Directory group name from csv in PowerShell?

If I have a .csv:
ClientCode,GroupCode
1234,ABC
1234,DEF
1235,ABC
1236,ABC
and I want to get a hashtable with ClientCode as key, and values to be all AD groups with ClientCode in it, for example:
ClientCode GroupCode
---------- ---------
1234 ClientGroup_InAD_1234, some_other_client_1234
1235 ClientGroup_InAD_1235, some_other_client_in_AD_1235
1236 ClientGroup_InAD_1236
How do I go about this?
Essentially, I have client groups in Active Directory and each client has a code which is the same as the 'ClientCode' in the csv. For example, I might have a client called 'Bob' which I have assigned a code '1234' to it. Therefore, the Group for Bob in the AD would be 'Bob_1234'. Essentially I want to be able to search for whatever groups have ClientCode in them. So i want to search for the all the AD groups that have '1234'. This would return 'Bob_1234' and whatever group in the AD also has '1234' in its name.
So far I have tried:
$clientTable = #{}
foreach($rec in $csv_data) {
$groups = #(get-adgroup -Filter "name -like '*$($rec.clientcode)_*'")
write-host "Found $($groups.count) group(s) for: $($rec.clientcode)"
$clientTable[$ClientCode] = #($groups)
}
$clientTable
but I'm not getting my desired output
You can use the loop like this. You will need to search with a * at the beginning of the name you are looking to find via the Filter.
foreach($rec in $csv) {
$clientCode = "*_$($rec.ClientCode)"
if (!($clientTable.ContainsKey($clientCode))) {
$names = Get-ADGroup -Filter 'Name -like $clientCode' | select Name
$clientTable[$clientCode] = $names -join ","
}
}
This will also check for any client IDs that have already been checked and ignore those.
If you want a hash table populated with the ClientCode value as the key name, you can do the following:
$clientTable = #{}
foreach($rec in $csv_data){
$groups = #(Get-ADGroup -Filter "Name -like '*_$($rec.ClientCode)'" | Select -Expand Name)
write-host "Found $($groups.count) group(s) for: $($rec.ClientCode)"
$clientTable[$rec.ClientCode] = $groups
}
$clientTable
Keep in mind here that each value in the hash table is an array of group names. If you want a single string with comma-delimited names, you can do $clientTable[$rec.ClientCode] = $groups -join "," instead.
You will need to de-duplicate the ClientCodes in the CSV before retrieving the groups.
Something like below should do it (assuming the ClientCode is always preceded by an underscore like in _1234 as shown in your examples)
$csv = Import-Csv -Path 'ClientGroupCodes.csv'
$clientTable = #{}
$csv | Select-Object -ExpandProperty ClientCode -Unique | ForEach-Object {
# $_ is a single clientcode in each iteration (string)
# get an array of goup names
$groups = #(Get-ADGroup -Filter "Name -like '*_$_'" | Select-Object -ExpandProperty Name)
Write-Host "Found $($groups.Count) group(s) for code : '$_'"
$clientTable[$_] = $groups -join ', '
}
$clientTable

Formatting variable with 2 outputs

Code:
$adgroups = Get-ADPrincipalGroupMembership $tag$ | select -ExpandProperty Name | Sort | Select-String "iSite"
Output:
DFSR Managed iSite Enterprise 4.4.542.2 WSA_Rad_A
DFSR Managed iSite Radiology 4.4.516.27 WSA_Rad_A
Basically one command generates two items (output using $variable | out-file C:\file.txt -Append) and when I go to open these in excel they format as one line like this:
DFSR Managed iSite Enterprise 4.4.542.2 WSA_Rad_A DFSR Managed iSite Radiology 4.4.516.27 WSA_Rad_A
Is there a way to break it up // add a new line after each item but still keep them both inside one variable?
Get-ADPrincipalGroupMembership $tag$ | select -ExpandProperty Name | Sort | Select-String "iSite" | ConvertTo-Csv -NoTypeInformation | Out-File C~\Desktop\Sites.csv
I would break up your request a bit.
First, you're using Select -Expand, which is going to discard all of the properties and only return the values for each object's Name. This is a problem because when you export it as a CSV, you're not going to have a heading. I think the lack of header is ultimately leading to the issue you're facing here.
Try this instead:
$adgroups = Get-ADPrincipalGroupMembership $tag$ | Where Name -like "*iSite*" |
select Name | Export-Csv c:\pathto\YourCsv.Csv
Finally, I don't think Select-String is doing you any favors. You could instead use the -like operator.

Filtering files by partial name match

I have a network share with 20.000 XML files in the format
username-computername.xml
There are duplicate entries in the form of (when a user received a new comptuer)
user1-computer1.xml
user1-computer2.xml
or
BLRPPR-SKB52084.xml
BLRSIA-SKB50871.xml
S028DS-SKB51334.xml
s028ds-SKB52424.xml
S02FL6-SKB51644.xml
S02FL6-SKB52197.xml
S02VUD-SKB52083.xml
Since im going to manipulate the XMLs later I can't just dismiss properties of the array as at the very least I need the full path. The aim is, if a duplicate is found, the one with the newer timestamp is being used.
Here is a snipet of the code where I need that logic
$xmlfiles = Get-ChildItem "network share"
Here I'm just doing a foreach loop:
foreach ($xmlfile in $xmlfiles) {
[xml]$xmlcontent = Get-Content -Path $xmlfile.FullName -Encoding UTF8
Select-Xml -Xml $xmlcontent -Xpath " "
# create [pscustomobject] etc...
}
Essentially what I need is
if ($xmlfiles.Name.Split("-")[0]) - duplicate) {
# select the one with higher $xmlfiles.LastWriteTime and store either
# the full object or the $xmlfiles.FullName
}
Ideally that should be part of the foreach loop to not to have to loop through twice.
You can use Group-Object to group files by a custom attribute:
$xmlfiles | Group-Object { $_.Name.Split('-')[0] }
The above statement will produce a result like this:
Count Name Group
----- ---- -----
1 BLRPPR {BLRPPR-SKB52084.xml}
1 BLRSIA {BLRSIA-SKB50871.xml}
2 S028DS {S028DS-SKB51334.xml, s028ds-SKB52424.xml}
2 S02FL6 {S02FL6-SKB51644.xml, S02FL6-SKB52197.xml}
1 S02VUD {S02VUD-SKB52083.xml}
where the Group property contains the original FileInfo objects.
Expand the groups in a ForEach-Object loop, sort each group by LastWriteTime, and select the most recent file from it:
... | ForEach-Object {
$_.Group | Sort-Object LastWriteTime -Desc | Select-Object -First 1
}

Powershell List groups and members from AD and export to CSV

I created a CSV with all the group names. The following script reads all the groups names from the "group.csv" and list the group and members.
Script:
Add-PSSnapin Quest.ActiveRoles.ADManagement
$csv = Get-Content "f:\Temp\group.csv"
$result = $csv | foreach-object {
$group=$_
get-qadgroupmember "$_" -sizelimit 0 -indirect | select-object samaccountname,#{n="GroupName";e={$group}}
}
$result | export-csv f:\temp\groupandmem.csv -notypeinformation
There are more than 1000 groups in the "group.csv" with a lot of members in each. The executing of the script stops with a memory problem and nothing is written to the groupandmem.csv because this is done at last.
I have the following questions:
Is is possible to:
- For each group in the "group.csv", list the group from CSV, search the group in the AD, display the members and write the group name and the members to the users groupandmem.csv. Do this for all the groups in the "group.csv".
-The groupandmem.csv is filled as follows:
Row 1 group,member1,members2,members3.......
Row 2 group2,member1,members2 etc.
If you start assigning things to variables then you are preventing powershell from "streaming" the users from one end of the pipe (AD) into the other end (the CSV file.) Instead, structure your pipeline like this:
Get-Content "f:\Temp\group.csv" | foreach-object {
$group = $_ # grab current group name
get-qadgroupmember $group -sizelimit 0 -indirect | `
select-object samaccountname,#{n="GroupName";e={$group}}
} | export-csv f:\temp\groupandmem.csv -notypeinformation
Now there is a true "pipeline" from start to finish: csv | foreach | get | transform | export
Before, you were backing things up by assigning everything into a variable before passing it onto the next command.
Updated: added $group to current capture group name (row)