I have a script that I want to import a CSV and create separate variables. One for WindowsKey and the other for OfficeKey
CSV Will look like:
School, WindowsKey, OfficeKey
Saints, BBBB-BBBB, XXXX-XXXX
Bears, YYYY-YYYY, ZZZZ-ZZZZ
Part of the Script:
$School = "Saints"
(Import-Csv k:\Keys.csv) | Where-Object {$_.School -eq $School}
This will make a table that looks like this:
School : Saints
WindowsKey: BBBB-BBBB
OfficeKey : XXXX-XXXX
How do I go about putting WindowsKey and OfficeKey into a variable that I can use later on in the script?
You can do it like this:
$csv = Import-Csv k:\keys.csv | Where-Object {$_.School -eq $School}
then you can access the data by dot notation, for example
$csv.WindowsKey
note that the properties contain arrays and not string data if you select multiple values so you will have to loop through it
Regards
Another approach (if you want to be able to access all keys by school) would be to create 2 hashtables for Windows and Office keys:
$csv = Import-Csv 'K:\Keys.csv'
$windowsKeys = #{}
$officeKeys = #{}
$csv | % {
$windowsKeys[$_.School] = $_.WindowsKey
$officeKeys[$_.School] = $_.OfficeKey
}
Then you can access the keys for each school like this:
$school = 'Bears'
"Windows Key ({0}): {1}" -f $school, $windowsKeys[$school]
"Office Key ({0}): {1}" -f $school, $officeKeys[$school]
Related
What I am trying to do is I import data from a csv file which has UserPrincipalnames and I am taking the names before the # symbol and then I want to export that data to a specific column in the same CSV file which in this case is o365Users.csv. I am able to write it out to a text file but I need to know how to export it out to Column G with the header name as SAM
This is my code:
$Addys = Import-Csv "C:\scripts\o365Users.csv"
$UPNs = $Addys.UserPrincipalName
foreach ($UPN in $UPNs) {
$Name = $UPN.Split("#")[0]
Write-Output $Name >> c:\scripts\o365Names.txt
}
To append a new column with the header SAM use Select-Object with a calculated property:
(Import-Csv 'C:\scripts\o365Users.csv') |
Select-Object -Property *,#{n='SAM';e={$_.UserPrincipalName.Split('#')[0]}}
If the new property has to be in a specific position you can't use the wildcard * but will have to enumerate all headers/columns/properties in the desired order, i.e.
(Import-Csv 'C:\scripts\o365Users.csv') |
Select-Object -Property ColA,ColB,ColC,ColD,ColE,ColF,#{n='SAM';e={$_.UserPrincipalName.Split('#')[0]}},ColH
replace Col_ with your real headers.
Due to enclosing the (Import-Csv) in parentheses you can export to the same file name (not recommended while still testing) - simply append
| Export-Csv 'C:\scripts\o365Users.csv' -NoTypeInformation
Here is a quick way to get just the output you are looking for. You would import the current CSV. Create an blank output array and in your loop add each name. Then export the CSV
$Addys = Import-Csv "C:\scripts\o365Users.csv"
$UPNs = $Addys.UserPrincipalName
[System.Collections.ArrayList]$Output = #()
foreach ($UPN in $UPNs) {
$Name = $UPN.Split("#")[0]
$Output.Add($Name) | Out-Null
}
$Output | Export-Csv -Path "C:\scripts\o365Users.csv" -NoTypeInformation
I'm new to PS, so your patience is appreciated.
I'm trying to grab data from (2) separate CSV files and then dump them into a new CSV with (2) columns. Doing this for (1) is easy, but I don't know how to do it for more.
This works perfectly:
Import-CSV C:\File1.csv | Select "Employee" | Export-CSV -Path D:\Result.csv -NoTypeInformation
If I add another Import-CSV, then it simply overwrites the existing data:
Import-CSV C:\File2.csv | Select "Department" | Export-CSV -Path D:\Result.csv -NoTypeInformation
How can I get columns A and B populated with the info result from these two commands? Thanks for your help.
I would have choose this option:
$1 = Import-Csv -Path "C:\Users\user\Desktop\1.csv" | Select "Employee"
$2 = Import-Csv -Path "C:\Users\user\Desktop\2.csv" | Select "Department"
$marged = [pscustomobject]#()
$object = [pscustomobject]
for ($i=0 ; $i -lt $1.Count ; $i++){
$object = [pscustomobject]#{
Employees = $1[$i].Employee
Department = $2[$i].Department}
$marged += $object
}
$marged | ForEach-Object{ [pscustomobject]$_ } | Export-Csv -Path "C:\Users\user\Desktop\3.csv" -NoTypeInformation -Force
I'll explain how I would do this, but I do it this way because I'm more comfortable working with objects than with hastables. Someone else may offer an answer using hashtables which would probably work better.
First, I would define an array to hold your data, which can later be exported to CSV:
$report = #()
Then, I would import your CSV to an object that can be iterated through:
$firstSet = Import-CSV .\File1.csv
Then I would iterate through this, importing each row into an object that has the two properties I want. In your case these are Employee and Department (potentially more which you can add easily).
foreach($row in $firstSet)
{
$employeeName = $row.Employee
$employee = [PSCustomObject]#{
Employee = $employee
Department = ""
}
$report += $employee
}
And, as you can see in the example above, add this object to your report.
Then, import the second CSV file into a second object to iterate through (for good form I would actually do this at the begining of the script, when you import your first one):
$secondSet = Import-CSV .\File2.csv
Now here is where it gets interesting. Based on just the information you have provided, I am assuming that all employees in the one file are in the same order as the departments in the other files. So for example, if I work for the "Cake Tasting Department", and my name is on row 12 of File 1, row 12 of File 2 says "Cake Tasting Department".
In this case it's fairly easy. You would just roll through both lists and update the report:
$i = 0
foreach($row in $secondSet)
{
$dept = $row.Department
$report[i].Department = $dept
$i++
}
After this, your $report object will contain all of your employees in one row and departments in the other. Then you can export it to CSV:
$report | Export-CSV .\Result.csv -NoTypeInformation
This works if, as I said, your data aligns across both files. If not, then you need to get a little fancier:
foreach($row in $secondSet)
{
$emp = $row.Employee
$dept = $row.Department
$report | Where {$_.Employee -eq $emp} foreach {$_.Department = $dept
}
Technically you could just do it this way anyway, but it depends on a lot of things. First of all whether you have the data to match in that column across both files (which obviously in my example you don't otherwise you wouldn't need to do this in the first place, but you could match across other fields you may have, like EmployeeID or DoB). Second, on the sovereignty of individual records (e.g., if you have multiple matching records in your first file, you will have a problem; you would expect duplicates in the second as there are more than one person in each department).
Anyway, I hope this helps. As I said there is probably a 'better' way to do this, but this is how I would do it.
I am attempting to merge two csv files together and select only two of their columns for use in a new csv. I don't understand why I cannot use the code I have already:
$Temp1 = (Import-csv "C:\path\APPcsv.csv" -header "APP") |
select-object APP
$Temp2 = (Import-csv "C:\path\ALLdb42APPs.csv"-header "NA1", "NA2", "Applications", "NA3", "Project") |
select-object Project
$CSV= #($temp1, $temp2) |
export-csv -path "C:\path\Why isn't this working.csv" -noTypeInformation
Here is an example line from each CSV:
CSV1 (ALLdb42APPs.csv)
"Current Application","Calculation","AdobeReaderDC-18.011.20036 V1 - Add Instalation Status: SUCCESSFUL","2018-05-16 08:54:17","DK ATM error main"
CSV2 (APPcsv.csv)
"DameWareService-10.0.0.0-x64 V2 - Add"
So your issue is because #($temp1,$temp2) doesn't combine the first element of $temp1 with the first element of $temp2, but instead makes a new collection which is all of $temp1's objects followed by all of $temp2.
Since $temp1 is objects with an APP property and $temp2 is objects with a Project, combining these into a collection doesn't make sense to export to a csv.
If $temp1 is a bag of apples and $temp2 is a bag of oranges, #($temp1,$temp2) isn't holding the bags together, it's dumping both into one bag on top of each other.
You could either join the two objects into one. Warren Frame has a well respected module Join-Object that could be used as James C pointed out, but your two csvs would need to share a column.
The other alternative is to use a for loop, then in each iteration take the value from each collection and create a new object with both values.
$Temp1 = (Import-csv "C:\path\APPcsv.csv" -header "APP") |
Select-Object -ExpandProperty APP
$Temp2 = (Import-csv "C:\path\ALLdb42APPs.csv"-header "NA1", "NA2", "Applications", "NA3", "Project") |
Select-Object -ExpandProperty Project
$LargestIndex = [math]::Max($temp1.count,$temp2.count)
$CombinedArray = For ($i=0; $i -le $LargestIndex; $i++) {
[pscustomobject]#{
APP = $temp1[$i]
Project = $temp2[$i]
}
}
$CombinedArray |
Export-Csv -Path "C:\path\Example.csv" -NoTypeInformation
Note: requires PowerShell 3+ for the pscustomobject way of creating objects.
I find myself continually faced with the need to store mixed-type data in some kind of a structure for later lookup.
For a recent example, I am performing data migration and I will store the old UUID, new UUID, source environment, target environment, and schema for an unknown number of entries.
I have been meeting this need by creating an array and inserting System.Objects with NoteProperty members for each of the columns of data.
This strikes me as a very clumsy approach but I feel like I may be limited by Powershell's functionality. If I need to, for example, locate all entries that used a particular schema, I write a foreach loop that sticks each entry with a matching schema name in a whole new array that I can return. I would really like the ability to more easily search for all objects that contain a member matching a particular value, modify existing members, etc.
Is there a better built-in data structure that will suit my needs, or is creating a custom object the right thing to do?
For reference, I'm doing something like this to create my structure:
$objectArray= #();
foreach(thing to process){
$tempObj = New-Object System.Object;
$tempObj | Add-Member -MemberType NoteProperty -Name "membername" -Value xxxxx
....repeat for each member...
$objectArray += $tempObj
}
If I need to find something in it, I then have to:
$matchingObjs = #()
foreach ($obj in $objectArray){
if($obj.thing -eq value){$matchingObjs += $obj}
}
This really sucks and I know there has to be a more elegant way. I'm still fairly new to powershell so I don't know what utilities it has to help me. I'm using v5.
With PowerShell 3.0 you could use a [PSCustomObject], here's an article on the different object creation methods.
Also setting the array equal to the output of the foreach loop will be more efficient than repeatedly recreating an array with +=.
$objectArray = foreach ($item in $collection) {
[pscustomobject]#{
"membername" = "xxxxx"
}
}
The Where-Object cmdlet or the .where() method looks like what you need in your second loop.
$matchingObjs = $objectArray | Where-Object {$_.thing -eq "value"}
It also sounds like you could use Where-Object/.where() to filter the initial data and just create an object which matches what you are looking for. For example:
$matchingObjs = $InputData |
Where-Object {$_.thing -eq "value"} |
ForEach-Object {
[pscustomobject]#{
"membername" = xxxxx
}
}
If your data can be expressed as key value pairs, then a hashtable will be the most efficient, see about_Hash_Tables for more info.
There is no built-in way to do what you are asking. One way is to segment your data into separate hashtables so you can do easy lookups by a common key, say the ID.
# Create a hastable for the IDs
$ids = #{};
foreach(thing to process){
$ids.Add($uid, 'Value')
}
# Find the $uid exists
$keyExists = $ids.Keys -Contains $uid
# Find value of stored for $uid
$keyValue = $ids[$uid]
As a side note, you don't have to create Syste.Object, you can simple do this:
$objectArray = #();
gci | % {
$objectArray += #{
'Key1' = 'Value 1'
'Key2' = 'Value 2'
}
}
If you need to compare complex objects, you can build them with #{} and then use Compare-Object on the two objects, just another idea.
For example, this will get a file listing of two different directories, and tell me what file exists or doesn't exist between the two directories:
$packages = (gci $boxStarterRepo -Recurse *.nuspec | Select-Object -ExpandProperty Name) -replace '.nuspec', ''
$packages += (gci $boxStarterPrivateRepo -Recurse *.nuspec | Select-Object -ExpandProperty Name) -replace '.nuspec', ''
$packages = $packages | Sort-Object
Compare-Object $packages $done
I have a large CSV file that looks like this named student.export.text
Student Number,Last Name,Middle Name,First Name,Schoolid,Grade Level,Dob
I'm trying to build an automated task that will run nightly so that another piece of software can understand the CSV correctly.
Here is my code, but I'm missing something that is causing an error. I am new to Powershell and I am hoping for some advice.
Any help will be greatly appreciated!
$Replacements = #{
"5" = "AE";
"7" = "ER";
"10" = "FM";
"12" = "HC";
"14" = "JH";
"18" = "LE";
#...]
}
Import-Csv .\student.export.text | ForEach-Object {
$_.Schoolid = $Replacements[$_.Schoolid]
$_
} | Export-Csv -NoTypeInformation .\new.csv
Here's one approach that can work.
# declare hash table with School ID to School Name mapping
$schoolIdsToNames = #{
"3" = "SchoolA";
"4" = "SchoolB"
}
# import the CSV file
$csv = Import-Csv "C:\input.csv";
# for each row, replace the School ID field with the School Name
foreach($row in $csv)
{
$row.Schoolid = $schoolIdsToNames[$row.Schoolid];
}
# export the modified CSV
$csv | Export-Csv "C:\replaced.csv" -NoTypeInformation;
In the first step, we set up a PowerShell hashtable (a sort of key-value pair list), then import the CSV file using Import-Csv and store it in the $csv variable. This cmdlet will create an object from every row of the CSV that we can manipulate easily. For each row, we simply replace the Schoolid field with the value assigned to the ID key in the $schoolIdsToNames hashtable. Finally, we export the CSV to another file.
Another, more PowerShell-ly approach would be something like this:
Import-Csv "C:\test\school.csv" | Select-Object *, #{ Name = "SchoolName"; Expression = { $schoolIdsToNames[$_.Schoolid] } } | Export-Csv "C:\test\replaced2.csv" -NoTypeInformation
This one-liner imports the CSV and sends it down the pipeline. For each row, we select all properties of the row using Select-Object and add a new property called SchoolName, setting its value using the same hash table-based technique as above. Finally, we export the object list to CSV.