I'm stuck trying to find a better way of modifying large (1000+ rows) CSV file than multiple foreach loops.
I have a CSV file with:
Name,login,ID,MGRID,MGRNAME
Bob Smith,bsmith,101,201,Drake Suzy
Suzy Drake,sdrake,201,300,Long Jane
John Bass,jbass,102,201,Drake Suzy
Jane Long,jlong,300,300,Long Jane
I'm trying to find the best way to import the csv and then set the MGRNAME for each employee to match the login of the corresponding MGR. I'd like to see:
Name,login,ID,MGRID,MGRNAME
Bob Smith,bsmith,101,201,sdrake
Suzy Drake,sdrake,201,300,jlong
John Bass,jbass,102,201,sdrake
Jane Long,jlong,300,300,jlong
I've tried importing the csv and then replacing the MGRNAME using:
$Sup = Import-Csv $Csvfile
Foreach ($MGR in $SUP){
$SUP1 = $MGR.MGRId
$SupID = ($sup | Where-Object {$_.login -eq $Sup1}).Login
Foreach ($ID in $Sup) {
($Sup | Where-Object {$_.MGRID -eq $SupID}).MGRNAME = $supId
}
}
I've also tried using something like:
$Users = Import-Csv $Csvfile
Foreach ($MGR in $users){
$supID=$MGR.MGRID
$RowIndex=[array]::Indexof($MGR.MGR.NAME,"$supID")
}
Any helpful suggestions welcome.
Thank you
here's one way to get the job done. [grin] what it does ...
fakes reading in a CSV
when ready to do this with real data, replace the entire #region/#endregion with a call to Import-Csv.
iterates thru the imported list
if the current user ID is the same as the MgrId, set the MgrName to the current login
otherwise, look up the Mgr with a .Where({}) method call with the mode set to First & set the MgrName with the resulting login
shows the result
the .Where({}) lookup could be slow if the import is large. if so, you likely otta replace that with a hashtable for lookups. however, premature optimization is bad coding, so i did not do that. [grin]
also, the export to CSV seems well documented, so i did not include that.
the code ...
#region >>> fake reading in a CSV file
# in real life, use Import-CSV
$UserList = #'
Name,login,ID,MGRID,MGRNAME
Bob Smith,bsmith,101,201,Drake Suzy
Suzy Drake,sdrake,201,300,Long Jane
John Bass,jbass,102,201,Drake Suzy
Jane Long,jlong,300,300,Long Jane
'# | ConvertFrom-Csv
#endregion >>> fake reading in a CSV file
foreach ($UL_Item in $UserList)
{
if ($UL_Item.Id -eq $UL_Item.MgrId)
{
$UL_Item.MgrName = $UL_Item.Login
}
else
{
$UL_Item.MgrName = $UserList.Where({$_.Id -eq $UL_Item.MgrId}, 'First', 1).Login
}
}
$UserList |
# remember - DO NOT use the "Format-*" cmdlets for anything other than _final output as plain text_ [*grin*]
Format-Table
the output ...
Name login ID MGRID MGRNAME
---- ----- -- ----- -------
Bob Smith bsmith 101 201 sdrake
Suzy Drake sdrake 201 300 jlong
John Bass jbass 102 201 sdrake
Jane Long jlong 300 300 jlong
Joining objects is a quite common activity in PowerShell, therefore I have created a 'Join-Object' cmdlet sometime ago which I still maintaining by adding features along with using a hashtable (for performance reasons as #Lee_Dailey mentiones) and adding self-join capabilities:
InnerJoin $UserList -on MgrId -eq id -discern '',MGR |
Select-Object Name, Login, ID, MGRID, MGRLogin | Format-Table
Name login ID MGRID MGRlogin
---- ----- -- ----- --------
Bob Smith bsmith 101 201 sdrake
Suzy Drake sdrake 201 300 jlong
John Bass jbass 102 201 sdrake
Jane Long jlong 300 300 jlong
Note that the column header MGRLogin doesn't exactly match the example in your question (which is actually inconsistent with the employee Name and - Login headers), but if you really want the same header you might do:
InnerJoin $UserList -on MgrId -eq id -discern '',MGR |
Select-Object Name, Login, ID, MGRID, #{n='MGRName'; e={$_.MGRLogin}} | Format-Table
For more details, see the embedded help (Help Join-Object) and In Powershell, what's the best way to join two tables into one?
Related
I have a CSV file for help desk calls. The same ticket might have 1,2, or even 5 records based on the number of updates it has. (One field is different, all other fields are identical).
I want to take the mostly-duplicate records and create one record with the differences concatenated into it. Having programmed in the past, but being a newbie to PowerShell, I could use some help.
So, based on a previous question I asked, here's what I have so far. Assuming data like this:
ID, Date, Comment
345, 1/1/16, Moss has reported a fire in the I/T Room
345, 1/1/16, Never mind, he has sent an e-mail about it.
346, 1/2/16, Someone on the 5th floor is complaining about a man under her desk.
347, 2/1/16, Jen says she has broken the Internet.
347, 2/1/16, Douglas is very angry, we need a fix ASAP!
347, 2/1/16, Roy was playing a joke on her. Closing ticket.
I have the following code:
$FileList = Import-Csv "Call List.csv"
$incidents = $FileList | Group ID
foreach($group in $incidents)
{
# What goes here?
}
How do I take the comments from the 2nd, 3rd, etc. line in the group, concatenate it to the comment in the first, and write the file out?
The Group-Object produces an object with Name and Group, Group containing all the items in that group. You can extract them and create a new object using something like this:
$incidents = $FileList | Group-Object ID | % {
New-Object psobject -property #{
ID = $_.Name
Date = $_.Group[0].Date
Comment = ($_.Group | Select -Expandproperty Comment) -Join "`n"
}
}
(not tested as I am currently on a Mac)
I'd first get a list of the unique IDs, for example:
$Ids = $FileList | Select-Object -ExpandProperty Id -Unique
Then I'd look through the list of tickets and build up a "report" for each ID:
foreach($Id in $Ids){
# Get all incident logs for this Id:
$logs = $FileList | ?{$_.Id -eq $Id}
$report = ""
foreach($log in $logs){
$report += $log.Date + ": " + $log.Comment + "; "
}
# Now you can write the text out
$report | Out-File $Outfile -Append
}
Hope that gives you an idea.
I have an array that I call $data.
I want to get the earliest dates from the $data array for each host in my csv file. The user will input a host and it will find the earliest date it was modified.
Hostname LastModified
HD 9/8/2012
LOG 9/15/2004
NETMAN 12/25/2004
NETMAN 5/5/2015
LOG 1/4/2013
LOG 6/6/2011
So if they input LOG, I want it to give me the earliest date.
Created on 9/15/2004
Code:
$data= import-csv ".\Earliest Date Template.csv"
$Hostname=Read-Host "Please enter Host Name"
$data | Foreach-Object {$_."Last Modified" = [DateTime]$_."Last Modified"; $_} | Group-Object Hostname| Foreach-Object {$_.Group | Sort-Object LastModified | Select-Object -First 1}
Grouping them does seem like the way to go but you don't need to do that. Just sort the entire list by date then select the last option from the list (that matches the host name you are looking for).
$hostname = Read-Host "Please enter Hostname"
$data | Sort-Object {[DateTime]$_."LastModified"} | Where-Object{$_.Hostname -eq $hostname} | Select -Last 1
You might need to do some user validation but something like this seems to work with your sample data:
Please enter Hostname: log
Hostname LastModified
-------- ------------
LOG 1/4/2013
If you then only want the date it would just be a matter of expanding the value from the result.
$data |
Sort-Object {[DateTime]$_."LastModified"} |
Where-Object{$_.Hostname -eq $hostname} |
Select -Last 1 -ExpandProperty LastModified
I am totally newbie to Access, I used to use Excel to handle my needs for a while.
But by now Excel has become too slow to handle such a big set of data, so I decided to migrate to Access.
Here is my problem
My columns are:
Number | Link | Name | Status
1899 | htto://example.com/code1 | code1 | Done
2 | htto://example.com/code23455 | code23455 | Done
3 | htto://example.com/code2343 | code2343 | Done
13500 | htto://example.com/code234cv | code234cv | Deleted
220 | htto://example.com/code234cv | code234cv | Null
400 | htto://example.com/code234cv | code234cv | Null
So I want a way to update Status of my rows according to numbers list.
For example I want to update Status column for multiple numbers to become Done
Simply I want to update "Null status" to become "Done" according to this number list
13544
17
13546
12
13548
13549
16000
13551
13552
13553
13554
13555
12500
13557
13558
13559
13560
30
13562
13563
Something like this
I tried "update query" but I don't know how to use criteria to solve this problem
In Excel I did that by "conditional formatting duplicates" -with my number list which I wanted to update-
Then "sort by highlighted color" then "fill copy" the status with the value
I know that Access is different but I hope that there is a way to do this task as Excel did.
Thanks in advance
From my understanding, You can try
Update TblA
Set TblA.Status="Done"
where Number in (13544,17,13546,....)
Or alternatively easy method is to pull these numbers in IN clause into its own table and use it like this
Update TblA
Set TblA.Status="Done" where Number in (select NumCol from NumTable )
or this solution may help you Here
Im trying to extract virtual network information for a VM using powershell, i tried using regular expression but for VM's with more than 1 NIC im unable to see output
Below is the output which i need..
PS C:\> get-vm sql.IAN01.Host | select -ExpandProperty virtualnetworkadapters | select virtualnetwork
VirtualNetwork
--------------
VirtualUplink
iSCSI1
iSCSI2
VirtualUplink
But when i try using regular expressions it does not give me an output, Network comes blank
PS C:\> Get-VM sql.IAN01.Host | Select #{Name="VMName";Expression={$_.name}},#{Name="Network
";Expression={#((get-vm $_.name | select -ExpandProperty virtualnetworkadapters).virtualnetwork)}}
VMName Network
------ -------
sql.IADPSQLHST1N01.Hosting
Can anyone please help me out!!
Try this:
Get-VM sql.IAN01.Host | Select-Object #{Name="VMName";Expression={$_.name}},#{Name='VirtualNetwork';e={$_.VirtualNetworkAdapters | Foreach-Object{$_.VirtualNetwork}}}
I'm new to PowerShell and am trying to query against my SQL server. I get the idea of creating a new-psdrive and then navigating to databases etc and have a line of code as
$dbs = (get-childitem
sqlserver:\sql\SERVER\INSTANCE\databases)
when I pipe the $dbs to a foreach, how would I get results of a collection of the database object? I am trying to read the extendedproperties of my test database.
This single query gives the results I want repeated for each database.
set-location
DRIVENAME:\databases\beagle_test\extendedproperties
get-childitem | select displayname,
value
any help very much appreciated.
I dont have SQL server handy to try this. Let me know the result
Set-Location DRIVENAME:\Databases
Get-ChildItem | % { Get-ChildItem $("$_.Name\extendedproperties") | Select DisplayName, Value }
Try this
Set-Location DRIVENAME:\Databases
Get-ChildItem | foreach-object { if (Test-Path $("$.Name\extendedproperties")) { Get-ChildItem $("$.Name\extendedproperties") | Select DisplayName, Value } }
The second line here is a single statement. What I am doing is to check if Extendedproperties exist and then get child item.
How about:
dir sqlserver:\sql\ServerName\InstanceName\Databases\*\ExtendedProperties\* |
select #{Name="Database";Expression={$_.Parent.Name}}, Name, Value
How about just:
dir SQLSERVER:\SQL\Server\Instance\databases\*\extendedproperties\* | % {select $_.displayname, $_.value}
so, many years later I am looking into my SO stats and see this old question and figure that my powershell skills have grown a little since 2010.
The use-case has long gone but I think what I was trying to achieve is this:
foreach ($db in $SMOServer.databases | Where-Object status -eq 'normal') {
$db.ExtendedProperties | Select-Object #{name = "DBName"; expression = {$db.Name}}, name, value
}
which gives results like this:
DBName Name Value
------ ---- -----
AdventureWorks2014 MS_Description AdventureWorks 2014 Sample OLTP Database
AdventureWorks2016 MS_Description AdventureWorks 2016 Sample OLTP Database