I am trying to take a filename such as: John_Doe_E_DOB_1/1/46_M(This is the gender)_ID_0000000_IMG_FileName_Date-of-File_1/1/15_Doc-page-1 And create a CSV file to open in Excel with column headers for: Last Name, First Name, MI, ID No, File Name, Date of File along with doc type. Here's my code so far:
Get-ChildItem -Path C:\Users\name\desktop\test -Recurse | ForEach-Object {$_ | add-member -name "Owner" -membertype noteproperty -value (get-acl $_.fullname).owner -passthru} | Sort-Object fullname | Select BaseName,Name,Owner | Export-Csv -Force -NoTypeInformation C:\Users\name\desktop\test\thing.csv
All this is doing is dropping that really long file name in at the top, and then adding the ext at the end in another column. Example:
John_Doe_E_DOB_1/1/46_M(This is the gender)_ID_0000000_IMG_FileName_Date-of-File_1/1/15_Doc-page-1 Would be in column 1 and
John_Doe_E_DOB_1/1/46_M(This is the gender)_ID_0000000_IMG_FileName_Date-of-File_1/1/15_Doc-page-1.txt <----- Would be the only difference in column 2
How can I split this up for over a million files, all different lengths, and sizes, and get it to break up into the categories listed above? All help would be greatly appreciated.
I would replace the Select stage of your pipeline with a call to a filter function like this:
filter GenObj {
$parts = $_.FullName.Split('_')
new-object pscustomobject -property #{
Owner = (get-acl $_.fullname).owner
FirstName = $parts[0]
LastName = $parts[1]
MiddleInitial = $parts[2]
# Fill in the rest
}
}
Get-ChildItem -Path C:\Users\name\desktop\test -Recurse |
Sort-Object fullname |
GenObj |
Export-Csv -Force -NoTypeInformation C:\Users\name\desktop\test\thing.csv
This will create a new custom object with all the properties on it that correspond to the parts of the filename you want to extract.
This string splitting approach may not work depending on how you handle names with no middle initial.
Also be aware that if you are processing a million files, the use of Sort-Object will cause every single FileInfo object (one for every file) to get buffered in memory so the sort can be performed. You may likely run out of memory and the command will fail. I would consider removing Sort-Object in this scenario.
Related
Hi I have a script that reads a csv file, creates a json file, checks the users in the file against a service, then i get the result as a json file.
I take that result and finds the users i csv file and creates a new file.
I do that with a where-object
But i need to add some extra values on every user before i export it to csv
This is my 2 lines for finding users and then export
$matches = $users | where-object { $_.number -in $response.allowedItemIds } | Select-Object -Property Number,Surname,Forename,Emailaddress
$matches | Export-Csv -path $Saved$savefile -NoTypeInformation -Append
Is that possible or do i need to do a for each?
Cheers
Assuming I've interpretted your question correctly, you should be able to use PowerShell's Calculated Properties for this purpose.
For example, if you wanted to add a field called "Date" and set the current Date/Time to each user row, you could do the following:
$matches = $users | where-object { $_.number -in $response.allowedItemIds } | Select-Object -Property Number,Surname,Forename,Emailaddress, #{Name="Date";Expression={Get-Date}}
The Expression value can either be a static value such as "StaticValue", a variable such as $i (useful if used as part of a loop, for example) or more complex value that is returned from other cmdlets (as in my example above)
I'm having trouble getting my head around how to take the two "properties" of each object within a json and output them into a csv. The two properties are "name" and "jobtitle" and I figure there should be a way to extract them.
$employees= ConvertFrom-Json $json
foreach ($person in $employees.information) {
# $person.name $person.jobtitle
}
No need for a loop, that should be bread-and-butter PowerShell territory. Feed the collection to a pipeline, use Select-Object to pick out the properties you care about, and then feed the pipeline to Export-CSV which handles the CSV header row, putting them on the same line, putting commas between them, quoting, etc.
$employees = ConvertFrom-Json $json
$employees.information | Select-Object name, jobtitle | Export-CSV -Path out.csv -NoTypeInformation
The only weird bit is -NoTypeInformation which stops it from putting PowerShell-specific markers for Integer/String/etc. types in the CSV, things which Excel (for example) won't read.
e.g. three objects with X,Y,Z properties - select just X and Z, and make them a CSV:
PS C:\> $Things = #(
[PSCustomObject]#{X=1; Y=2; Z=3}
,[PSCustomObject]#{X=4; Y=5; Z=6}
,[PSCustomObject]#{X=7; Y=8; Z=9}
)
$Things | Select-Object X,Z | ConvertTo-Csv -NoTypeInformation
"X","Z"
"1","3"
"4","6"
"7","9"
I'm trying to import users into an active directory using a CSV file and a powershell script. I create a CSV with the headers normally associated with an AD object:
mail,name,givenName,middleName,surname,company,department,title,plaintextPassword,path,description,userPrincipalName
...and filled it up.
Now I want to use Powershell's new-aduser cmmdlet to generate users for each item in this sheet - the problem I'm having is that new-aduser requires a SecureString, not just a normal string for an account's password. Skipping this conversion results in my users being created correctly, but with no passwords and their account disabled.
The command I'm using is as follows:
import-csv .\users.csv | add-member -passthru -memberType NoteProperty -value {$_ | select plaintextPassword | ConvertTo-SecureString -fromplaintext -force}
The result is user records like the following:
mail : tom.fubar#contoso.com
name : tom.fubar
givenName : Tom
middleName :
surname : Fubar
company : Contoso
department : IT
title : Technician
accountPassword : LongPasswordThatFitsADComplexityRequirements123!
path : OU=UserAccounts,OU=IT,OU=employees,DC=contoso,DC=com
description :
userPrincipalName : tom.fubar#contoso.com
encodedPassword : {$_ | select accountPassword | ConvertTo-SecureString -asplaintext -force}
The bit of code that should be evaluated for converting the plaintext password to a SecureString is being passed verbatim, rather than executed inline.
What is the proper way to force the code block to be evaluated, and use its result as the argument to New-Member -value?
Tried:
Enclosing the script block in $(...) - Results in a null NoteProperty added to the object
Replacing the {...} with $(...) - Results in a null NoteProperty added to the object
(as shown by piping the whole command to Get-Member)
Eris has posted a perfectly valid workaround, but to answer why it won't work for you, it's because $_ doesn't apply to any old script block. It's "special" and used only in certain contexts.
Additionally, -NotePropertyValue expects a static value.
Instead, you could add a ScriptProperty like so:
import-csv .\users.csv |
add-member -passthru -memberType ScriptProperty -value {$this.plaintextPassword | ConvertTo-SecureString -fromplaintext -force}
In this context for example, $_ is not even used; you have to use $this to refer to the parent object.
This does result in the script being processed every time the property is accessed though. If you don't want that, and want to do a static value assignment that's calculated per object, then you must enumerate yourself:
import-csv .\users.csv | ForEach-Object {
$val = $_ | select plaintextPassword | ConvertTo-SecureString -fromplaintext -force
$_ | add-member -passthru -memberType NoteProperty -value $val -Force
}
One solution I've found is to not bother with Add-Member, instead use a calculated property like so:
import-csv .\users.csv |
select -Property *, #{
n="encodedPassword";
e={$_.plaintestPassword | ConvertTo-SecureString -fromplaintext -force}}
(Removed broken add-member after comment from #PetSerAl)
PowerShell newbie here,
I need to:
Get text files in recursive local directories that have a common string, students.txt in them.
Get another string, gc.student="name,name" in the resulting file set from #1 and get the name(s).
Put the filename from #1, and just the name,name from #2 (not gc.student="") into a hashtable where the filename is paired with its corresponding name,name.
Output the hashtable to an Excel spreadsheet with 2 columns: File and Name.
I've figured out, having searched and learned here and elsewhere, how to output #1 to the screen, but not how to put it into a hashtable with #2:
$documentsfolder = "C:\records\"
foreach ($file in Get-ChildItem $documentsfolder -recurse | Select String -pattern "students.txt" ) {$file}
I'm thinking to get name in #2 I'll need to use a RegEx since there might only be 1 name sometimes.
And for the output to Excel, this: | Export-Csv -NoType output.csv
Any help moving me on is appreciated.
I think this should get you started. The explanations are in the code comments.
# base directory
$documentsfolder = 'C:\records\'
# get files with names ending with students.txt
$files = Get-ChildItem $documentsfolder -recurse | Where-Object {$_.Name -like "*students.txt"}
# process each of the files
foreach ($file in $files)
{
$fileContents = Get-Content $file
$fileName = $file.Name
#series of matches to clean up different parts of the content
#first find the gc.... pattern
$fileContents = ($fileContents | Select-String -Pattern 'gc.student=".*"').Matches.Value
# then select the string with double quotes
$fileContents = ($fileContents | Select-String '".*"').Matches.Value
# then remove the leading and trailing double quotes
$fileContents = $fileContents -replace '^"','' -replace '"$',''
# drop the objects to the pipeline so that you can pipe it to export-csv
# I am creating custom objects so that your CSV headers will nave nice column names
Write-Output [pscustomobject]#{file=$fileName;name=$fileContents}
} | Export-Csv -NoType output.csv
I have below powershell code using which am saving results into csv file but I couldnt save them in csv file.
[Reflection.Assembly]::LoadWithPartialName("Microsoft.AnalysisServices")
$SSASServerName = "SSAS_ServerName"
$SSASDB = "TESTDB"
$SSASServer = New-Object Microsoft.AnalysisServices.Server
$SSASServer.Connect($SSASServerName)
$SSASDatabase = $SSASServer.Databases.Item($SSASDB)
$SSASDatabase.Roles | Select-Object Name, Members | Export-Csv C:\dev\psout\test.Csv
pause
This script extracts name of the role and members associated to that role. one role can have multiple members.
I tried above script, it exports role but in Members field, I see string "Microsoft.AnalysisServices.RoleMemberCollection" for all the roles.
If I do not export to csv, I can view the members in either ps window or text file.
what am i missing?
You can only export values that can be represented as a string to a csv-file. Members is a collection-object that may include multiple RoleMember-objects, so you need use a calculated property to access the Name-property inside each RoleMember. How to approach this depends on the desired output.
You can join the objects Name-property to a single string
$SSASDatabase.Roles |
Select-Object Name, #{n="Members";e={ ($_.Members | % { $_.Name }) -join '; '}} |
Export-Csv C:\dev\psout\test.Csv -NoTypeInformation
Role1,"User1; User2"
Role2,"User3; User4"
Or you could make one row in the csv-file "per row per member" which I usually prefer since it's easier to filter in Excel.
$SSASDatabase.Roles | ForEach-Object {
#Store role-reference so we can access it later inside the member-foreach
$r = $_
$r.Members | ForEach-Object {
#Store member-reference so it's available inside Selec-Object
$m = $_
$r | Select-Object Name, #{n="Member";e={ $m.Name }}
}
} | Export-Csv C:\dev\psout\test.Csv -NoTypeInformation
Role1,User1
Role1,User2
Role2,User3
...