Splitting CSV cell (but leave the original as is) using Powershell - powershell

I'm trying to add some pdf's files from a directory into csv file.
I'm using the below PowerShell script to add the PDFs but the issue is that I need to split (but leave the original PDF path on each file as is) the path numbers into calls.
Is there any way to accomplish this one?
Get-ChildItem -Recurse "C:\Users\alon\Desktop\MYpdf\" |
ForEach-Object {
$_ | Add-Member -Name "Owner" -MemberType NoteProperty -Value (Get-Acl $_.FullName).Owner -PassThru
} |
Sort-Object FullName |
Select FullName, CreationTime, LastWriteTime, Length, Owner |
Export-Csv -Force -NoTypeInformation "C:\Users\alon\Desktop\MYpdf\directory.csv"
The output should be like this:

You mean you want to add the numbers from the filename as additional fields in your output? I would split each file's basename and construct custom objects from that information and the file metadata:
Get-ChildItem ... |
ForEach-Object {
$numbers = $_.BaseName -split '_'
[PSCustomObject]#{
FullName = $_.FullName
Company = [int]$numbers[0]
Invoice = [int]$numbers[1]
Deal = [int]$numbers[2]
Customer = [int]$numbers[3]
Autonumber = [int]$numbers[4]
CreationTime = $_.CreationTime
LastWriteTime = $_.LastWriteTime
Length = $_.Length
Owner = (Get-Acl $_.FullName).Owner
} |
Sort-Object FullName |
Export-Csv ...
Using calculated properties would also work, but in this case constructing new objects is arguably the simpler approach.
Note that the [PSCustomObject] type accelerator requires PowerShell v3 or newer. On older versions you can create the objects via New-Object and then use Select-Object to get the properties in a defined order.

Related

How to add a string to the output from powershell

I use this to get a list of folders containing .h files.
**
$type = "*.h"
$HDIRS = dir .\$type -Recurse |
Select-Object Directory -Unique |
Format-Table -HideTableHeaders
** It gives me a list of folders.
Now I want "-I " before every foldername. Common string manipulation doesn't seem to work
You still have rich objects after the select so to manipulate the strings you have to reference the one property you've selected "Directory"
$type = "*.h"
$HDIRS = Dir .\$type -Recurse |
Select-Object Directory -Unique |
ForEach-Object{
$_.Directory = "-I" + $_.Directory
$_
} |
Format-Table -HideTableHeaders
This will result in $HDIRS looking like a list of folder paths like -IC:\temp\something\something...
However, the format output objects are generally not suitable for further consumption. It looks like you're interested in the strings you could simply make this a flat array of strings like:
$type = "*.h"
$HDIRS = Dir .\$type" -Recurse |
Select-Object -ExpandProperty Directory -Unique |
ForEach-Object{ "-I" + $_ }
The mantra goes filter left, format right.
Our data:
$type = '.\*.h'
Get-ChildItem -Path $type -Recurse
The manipulation (filter):
Select-Object { "-I $($_.Directory)" } -Unique
And the format:
Format-Table -HideTableHeaders
In many cases, PowerShell cmdlets allow you to pass scriptblocks (closures) to evaluate to values and that's what I'm doing above with the Select-Object call.

Powershell - Sorting and selecting files in foreach loop

I'm trying to create a script that will find the most recent build_info files from multiple install locations in a server's directory, select the "version: " text from each file, and compare them to see if they're all the same (which is what we hope for), or if certain install locations have different versions. As a bonus, it would also be nice to have each path's install version have its own variable so that if I have to output any differences, I can say which specific paths have which versions. For example, if something is installed in Path1, Path2, and Path3, I want to be able to say, "all paths are on version 3.5," or "Path1 is version 1.2, Path2 is version 3.5, Path3 is version 4.8."
Here's a neater list of what I'm trying to do:
Loop through folders in a directory.
For each folder, sort the txt files with a specific name in that path by Creation Date descending and select the most recent.
Once it has the most recent files from each path, Select-String a specific phrase from each of them. Specifically, "version: ".
Compare the version from each path and see if all are the same or there are differences, then output the result.
This is what I've been able to write so far:
$Directory = dir D:\Directory\Path* | ?{$_.PSISContainer};
$Version = #();
foreach ($d in $Directory) {
$Version = (Select-String -Path D:\Directory\Path*\build_info_v12.txt -Pattern "Version: " | Select-Object -ExpandProperty Line) -replace "Version: ";
}
if (#($Version | Select -Unique).Count -eq 1) {
Write-Host 'The middle tiers are all on version' ($Version | Select -Unique);
}
else {
Write-Host 'One or more middle tiers has a different version.';
}
I've had to hard code in the most recent build_info files because I'm not sure how to incorporate the sorting aspect into this. I'm also not sure how to effectively assign each path's result to a variable and output them if there are differences. This is what I've been messing around with as far as the sorting aspect, but I don't know how to incorporate it and I'm not even sure if it's the right way to approach this:
$Recent = Get-ChildItem -Path D:\Directory\Path*\build_info*.txt | Sort-Object CreationTime -Descending | Select-Object -Index 0;
You can use Sort-Object and Select-Object to determine the most recent file. Here is a function that you can give a collection of files to and it will return the most recent one:
function Get-MostRecentFile{
param(
$fileList
)
$mostRecent = $fileList | Sort-Object LastWriteTime | Select-Object -Last 1
$mostRecent
}
Here is one possible solution:
Get-ChildItem "D:\Directory\Path" -Include "build_info*.txt" -File -Recurse |
Group-Object -Property DirectoryName |
ForEach-Object {
$_.Group |
Sort-Object LastWriteTime -Descending |
Select-Object -First 1 |
ForEach-Object {
New-Object -TypeName PsCustomObject |
Add-Member -MemberType NoteProperty -Name Directory -Value $_.DirectoryName -PassThru |
Add-Member -MemberType NoteProperty -Name FileName -Value $_.Name -PassThru |
Add-Member -MemberType NoteProperty -Name MaxVersion -Value ((Select-String -Path $_.FullName -Pattern "Version: ").Line.Replace("Version: ","")) -PassThru
}
}
This will produce a collection of objects, one for each directory in the tree, with properties for the directory name, most recent version and the file we found the version number in. You can pipe these to further cmdlets for filtering, etc.

Sum of file folder size based on file/folder name

I have multiple folders across a number of SQL Servers that contain hundreds/thousands of databases. Each database comprises of three elements:
<dbname>.MDF
<dbname>.LDF
<dbname>files (Folder that contains db files/attachments)
I need to marry these files together and add up their total size, does anyone have any advice on how to do this?
EDIT : Just to clarify, I'm currently able to output the filesizes of the MDF/LDF files, I have a separate script that summarises the folder sizes. I need a method of adding together a .MDF/.LDF/DBFiles folder when their name matches. Bearing in mind all of the files are prefixed with the database name.
EDIT #2: The 2 options given so far sum together the .mdf/.ldf files with no problem, but do not add the folder size of the DBFiles folder. Does anyone have any input on how to amend these scripts to include a folder beginning with the same name.
First provided script:
$root = 'C:\db\folder'
Get-ChildItem "$root\*.mdf" | Select-Object -Expand BaseName |
ForEach-Object {
New-Object -Type PSObject -Property #{
Database = $_
Size = Get-ChildItem "$root\$_*" -Recurse |
Measure-Object Length -Sum |
Select-Object -Expand Sum
}
}
Second provided script:
gci "c:\temp" -file -Include "*.mdf", "*.ldf" -Recurse |
group BaseName, DirectoryName |
%{new-object psobject -Property #{FilesAndPath=$_.Name; Size=($_.Group | gci | Measure-Object Length -Sum).Sum } }
EDIT #3:
Thanks to Ansgar (below), the updated solution has done the trick perfectly. Updating question with final solution:
$root = 'C:\db\folder'
Get-ChildItem "$root\*.mdf" | Select-Object -Expand BaseName |
ForEach-Object {
New-Object -Type PSObject -Property #{
Database = $_
Size = Get-ChildItem "$root\$_*\*" -Recurse |
Measure-Object Length -Sum |
Select-Object -Expand Sum
}
}
Enumerate just the .mdf files from your database folder, then enumerate the files and folders for each basename.
$root = 'C:\db\folder'
Get-ChildItem "$root\*.mdf" | Select-Object -Expand BaseName |
ForEach-Object {
New-Object -Type PSObject -Property #{
Database = $_
Size = Get-ChildItem "$root\$_*\*" -Recurse |
Measure-Object Length -Sum |
Select-Object -Expand Sum
}
}
if you want the sum of sise files database by dir and name file (without extension), try it
gci "c:\temp" -file -Include "*.mdf", "*.ldf" -Recurse |
group BaseName, DirectoryName |
%{new-object psobject -Property #{FilesAndPath=$_.Name; Size=($_.Group | gci | Measure-Object Length -Sum).Sum } }
Modifiy a little the include gci if necessary

List of items in a folder using sub string of filename

I have a directory which contains .xls files named as follows:
Recon_[Account No]_[YYYYMMDD].xls
e.g:
Recon_9020111006076954416_20131216.xls
The Account number can be any number of characters between 16 and 20.
I need to get a list of items in this folder - but only the account numbers.
What would be FANTASTIC is if I could get a list of account numbers and then next to them the date the file was created (which can be the datestamp in the file name or the last modified date of the file), in YYYY/MM/DD format, sorted by date.
Like this:
9020111006076954416 2013/12/16
10201129080000235952 2013/12/17
I then need this list of accounts in a text file, or even better, an excel file. Any ideas?
Give this a try:
Get-ChildItem -Filter *.xls | Where-Object {$_.BaseName -match '^Recon_\d{16,20}_\d+$'} | ForEach-Object{
$id,$date = $_.BaseName.Split('_')[1..2]
New-Object PSObject -Property #{
AccountNumber = $id
DateCreated = $date.Insert(4,'/').Insert(7,'/')
}
} | Export-Csv itemList.csv -NoTypeInformation
Fairly, easy, actually:
First obtain the raw data
Get-ChildItem *.xls |
Then extract the properties you need from it:
ForEach-Object {
if ($_.Basename -match '^Recon_(?<account>\d+)_(?<date>\d+)$') {
$_ | Add-Member NoteProperty AccountNumber $Matches.account
}
} |
Select those properties you are interested in (we are still dealing with the original FileInfo object, we just added the account number to it):
Select-Object AccountNumber,LastWriteTime
You could make the header nicer as well:
Select-Object #{l='Account Number'; e={$_.AccountNumber}}, #{l='Date'; e={$_.LastWriteTime}}
At this point you have something you can display on screen nicely. You can then continue formatting the data by piping it into another ForEach-Object:
ForEach-Object {
'{0}`t{1:yyyy-MM-dd}' -f $_.AccountNumber, $_.LastWriteTime
}
or convert it to CSV (which Excel can then open) by piping into ConvertTo-Csv:
ConvertTo-Csv foo.csv
To recap:
$data = Get-ChildItem *.xls |
ForEach-Object {
if ($_.Basename -match '^Recon_(?<account>\d+)_(?<date>\d+)$') {
$_ | Add-Member NoteProperty AccountNumber $Matches.account
}
} |
Select-Object AccountNumber,LastWriteTime
$data | ForEach-Object {
"{0}`t{1:yyyy-MM-dd}" -f $_.AccountNumber, $_.LastWriteTime
} | Out-File foo.txt
$data | ConvertTo-Csv foo.csv
Get all files of this directory. in a loop get file name and split it by '_'. the second item of array is account number and the third one is date.

Selecting latest file from a folder and copy it to another file using powershell script

I am new to powershell scripts and need some help.
We have a folder \Output. It will have the files in following format :
abc_1.dat
abc_2.dat
xyz_1.dat
abc_3.dat
pqr_2.dat
......
Now I want to find the latest file starting with "abc" (e.g., abc_3.dat) and copy the data to abc.dat. Similarly for xyz and pqr. These files will keep on being added.
First, you need to find your list of unique prefixes:
$prefixes = Get-ChildItem \Output |
Where-Object { -not $_.PsIsContainer } |
Foreach-Object { $_.Name.Substring(0, 3) } |
Select-Object -Unique
Then, for each prefix, find the latest/highest number and copy it to the preferred file:
$latest = $prefixes |
Foreach-Object {
Join-Path \Output "$_*" |
Get-ChildItem |
Add-Member NoteProperty -Name ID -Value { [int] ($_.BaseName -split '_')[1] } -PassThru |
Sort-Object ID -Descending |
Select-Object -First |
Copy-Item -Destination \Output\$_.dat
}