I'm trying to get the script to read the first line of files.txt, grab the data metadata requested and then output the .xml, move onto the next line and repeat.
I expect each line to have its own individual file with the meta data and then the next line to do the same.
Currently it creates all the individual files, but the data is combined and duplicated across them.
The files.txt contains the full path and files that is being
collected with the metadata e.g.
D:\data\testscript.ps1
D:\data\workingfile.doc
C:\Windows\temp\output.txt
Filesv2.txt contain the filename of the xml output and is consistent
in array with files.txt e.g
D_data_testscript.ps1
D_data_workingfile.doc
C_Windows_temp_output.txt
$logdir = "C:\Users\gnome\Documents"
$inputPath = Get-Content -Path "C:\Users\gnome\Documents\files.txt"
$inputSave = Get-Content -Path "C:\Users\gnome\Documents\filesv2.txt"
#Get-*
$hash = Get-FileHash -Path $inputPath
$acl = Get-Acl -Path $inputPath | Select-Object *
$metadata = Get-ChildItem -Path $inputPath | Select-Object *
#Loop each directory in $inputPath
#ForEach ($path in $inputPath){
$output = ForEach ($path in $inputPath){
Write-host Checking $path
ForEach($inputSave in $inputSave){
#{
#$log = "$logdir\$inputSave.xml"
sha256Hash = $hash
acl = $acl
metadata =$metadata
}
$output | Export-Clixml "$logdir\test1_$inputSave.xml"
}
}
'''
From your comment, files.txt stores full path and filenames and filesv2.txt has new names for these files according to some naming convention to be used for the output xml filename.
Having both arrays separate from eachother in separate files is somewhat accident-prone, because all that links the file name to the convention name is the index in both arrays..
Below first creates a Hashtable from these arrays assuming the indices match and both arrays have the same number of elements
$logdir = "C:\Users\gnome\Documents"
$inputPath = #(Get-Content -Path "C:\Users\gnome\Documents\files.txt") # full path and filenames
$inputSave = #(Get-Content -Path "C:\Users\gnome\Documents\filesv2.txt") # naming convention for the output
# create a Hashtable where the input from files.txt is key and the naming convention for the output xml is value
$filesHash = #{}
for ($i = 0; $i -lt $inputPath.Count; $i++) {
$filesHash[$inputPath[$i]] = $inputSave[$i]
}
# now iterate
$filesHash.GetEnumerator() | ForEach-Object {
Write-host Checking $_.Key
$output = [PsCustomObject]#{
sha256Hash = Get-FileHash -Path $_.Key -Algorithm SHA256
acl = Get-Acl -Path $_.Key
metadata = Get-Item -Path $_.Key
}
$outFile = Join-Path -Path $logdir -ChildPath ('{0}.xml' -f $_.Value)
$output | Export-Clixml -Path $outFile
}
Related
I need to find relative paths of folders and its files with length in MB in separate csv columns and compare that csv file with another csv file and print unmatched filepaths with length in another csv in absolute path
$srcpth = "C:\Users\vavenkatamanoj\Downloads"
$files = Get-ChildItem -Path $srcpth -File -Recurse
foreach ($f in $files)
{
$filen = $f.Name
$relativePath = $f.fullname.remove(0,($srcpth.length))
$filesize = $f.Length
Write-Output "$relativePath,$filesize" | Out-File C:\Users\vavenkatamanoj\Downloads\check.csv -Append
}
I try this script to get relative paths with size. It is ok but filepath and length are returned in the same column; I need separate columns. Can anyone help me?
$srcpth = "C:\Users\vavenkatamanoj\Downloads"
$files = Get-ChildItem -Path $srcpth -File -Recurse
$result = foreach ($f in $files) {
[pscustomobject][ordered]#{
fileName = $f.Name
RelativePath = $f.fullname.remove(0,($srcpth.length))
FileSize = $f.Length
}
}
$result | Export-Csv "c:\temp\output.csv" -NoTypeInformation -Append
Use PSCustomObject for creating structured data. Please find the link below for more info:
https://learn.microsoft.com/en-us/powershell/scripting/learn/deep-dives/everything-about-pscustomobject?view=powershell-7.3
Continuing from my comment,
Why not create a CSV file that has both the Length, the Absolute and the Relative path all in-one?
$srcpth = 'C:\Users\vavenkatamanoj\Downloads'
# needed for Resolve-Path -Relative
$currentPath = (Get-Location).Path
Set-Location $srcpth
# you could now remove the -Path $srcpth if you like
$result = Get-ChildItem -Path $srcpth -File -Recurse | ForEach-Object {
# output Objects
[PsCustomObject]#{
FileName = $_.Name
FileSize = $_.Length
RelativePath = $_.FullName | Resolve-Path -Relative
AbsolutePath = $_.FullName
}
}
# now, output the data as CSV
$result | Export-Csv -Path 'C:\Users\vavenkatamanoj\Downloads\check.csv' -NoTypeInformation
# restore the current location
Set-Location $currentPath
I am using the following script to read a list of file names which are then deleted. Is there a way can get an output of the date and time each file is deleted?
$targetFolder = "D:\" $fileList = "C:\DeleteList.txt" Get-ChildItem
-Path "$targetFolder\*" -Recurse -Include #(Get-Content $fileList) | Remove-Item -Verbose
Thanks for any help.
You could keep track of the files that are deleted and the time of deletion by outputting an object with the file's fullname and current date.
This output can then be saved as structured CSV file
$targetFolder = "D:\"
$fileList = Get-Content -Path "C:\DeleteList.txt"
$deleted = Get-ChildItem -Path $targetFolder -Recurse -Include $fileList | ForEach-Object {
# output an object with the current date and the file FullName
$_ | Select-Object #{Name = 'DeletedOn'; Expression = {(Get-Date)}}, FullName
$_ | Remove-Item -WhatIf
}
# output on screen
$deleted | Format-Table -AutoSize
# output to csv file
$deleted | Export-Csv -Path 'C:\RemovedFiles.csv' -NoTypeInformation
Remove the -WhatIf safety-switch if you are satisfied with the results shown on screen.
Would this work?
$targetFolder = "D:"
$fileList = "C:\DeleteList.txt"
$Files = Get-ChildItem -Path "$targetFolder" -Recurse -Include #(Get-Content $fileList)
# Once you have the desires files stored in the $Files variable, then run a Foreach loop.
$Obj = #() # create an array called $Obj
Foreach ($File in $Files)
{
# store info in hash table
$hash = #{
DateTime = (get-date)
fileName = $File.name
fullpath = $File.fullname
}
Write-Host "deleting file $($file.name)" -for cyan
Remove-Item $File.fullname # *** BE VERY CAREFUL!!!***
# record information in an array called $Obj
$Obj += New-Object psobject -Property $hash
}
$Obj | select fileName, DateTime | Export-csv C:\...
I need assistance in filtering what is going in to my output.
Here is my code:
$FolderPath = Get-ChildItem -Directory -Path "Z:\D482\F11\SECURE" -Recurse -Force
$Output = #()
ForEach ($Folder in $FolderPath) {
$Acl = Get-Acl -Path $Folder.FullName
ForEach ($Access in $Acl.Access) {
$Properties = [ordered]#{'Folder Name'=$Folder.FullName;'Group/User'=$Access.IdentityReference }
$Output += New-Object -TypeName PSObject -Property $Properties
}
}
$Output | ConvertTo-Csv | Out-File C:\Temp\Secured.txt
My output looks like this:
#TYPE System.Management.Automation.PSCustomObject
"Folder Name","Group/User"
"Z:\D482\F11\SECURE\QA\CDM\To_Load\Duals\Load_Completed","S-1-5-21-1275210071-879983540-1801674531-105509"
"Z:\D482\F11\SECURE\QA\Files\CDM\To_Load\Duals\Load_Completed","S-1-5-21-1275210071-879983540-1801674531-121910"
"Z\D482\F11\SECURE\QA\D482\To_Load\Duals\Load_Completed","DOMAIN\CXL3708"
In my output, I only want lines that contain our domain name ( as illustrated by the line with DOMAIN in it.
I have not been successful - either I get nothing, or I get error messages in the console.
here is one way to do the job ... [grin]
what it does ...
sets the constants
builds a parameter splat for the Get-ChildItem call
grabs the dirs from the source path
iterates thru the dir list
gets the acl list for the current dir & filters for those that start with the required domain name
note that i don't have a .IdentityReference property in my ACL, so i used .Owner instead.
iterates thru those acl items
builds a [PSCustomObject] for the current acl
sends that out to the $AccessInfo collection
displays the content of the above on screen
saves the collection to a csv file
the code ...
$SourcePath = $env:TEMP
$DomainName = $env:USERDOMAIN
$ReportFile = "SO_Erich_Powershell - How To Filter Output.csv"
$FullReportFile = Join-Path -Path $env:TEMP -ChildPath $ReportFile
$GCI_Params = #{
LiteralPath = $SourcePath
Directory = $True
Force = $True
Recurse = $True
ErrorAction = 'SilentlyContinue'
}
$DirList = Get-ChildItem #GCI_Params
$AccessInfo = foreach ($DL_Item in $DirList)
{
$AclList = Get-Acl -LiteralPath $DL_Item.FullName |
Where-Object {
$_.Owner -match "^$DomainName"
}
foreach ($AL_Item in $AclList)
{
[PSCustomObject]#{
DirName = $DL_Item.FullName
# my single system has no ".IdentityReference" property
# so i used ".Owner"
GroupOrUser = $AL_Item.Owner
}
}
}
# display the data
$AccessInfo
# send to a csv file
$AccessInfo |
Export-Csv -LiteralPath $FullReportFile -NoTypeInformation
truncated screen output ...
DirName GroupOrUser
------- -----------
C:\Temp\1 MySysName\AnotherUserName
C:\Temp\2 MySysName\AnotherUserName
C:\Temp\3 MySysName\AnotherUserName
[*snip ...*]
C:\Temp\vscode-update-system-x64 MySysName\MyUserName
C:\Temp\WPF MySysName\MyUserName
C:\Temp\mbam\qt-jl-icons MySysName\MyUserName
truncated csv file content ...
"DirName","GroupOrUser"
"C:\Temp\1","MySysName\AnotherUserName"
"C:\Temp\2","MySysName\AnotherUserName"
[*snip ...*]
"C:\Temp\WPF","MySysName\MyUserName"
"C:\Temp\mbam\qt-jl-icons","MySysName\MyUserName"
I need to add text to the end of the header in a text/csv file and then add other text (date) at the end of each line below the header. Adding the text part is working fine but it's the exporting to a csv that's not working as expected.
The expected output is (bold text is the added text);
"Folder Name","Files","Folders","Size","Comment","ReportDate"
"\\server\share\folder","2,029,756","819,527","1,785,490,958,735"," ","1/10/2020"
Instead I'm getting;
"Length"
"61"
"74"
"88"
"118"
$Path = "C:\temp\"
$files = Get-ChildItem $Path -filter '*.csv'
ForEach ($file in $files)
{
$datetmp = $file.PSChildName.Substring(0,10)
$datetmp = $datetmp.split("_")
$date = $datetmp[1] + "/" + $datetmp[2] + "/" + $datetmp[0]
$Fullpath = $Path + $file
[System.Collections.ArrayList]$content = Get-Content $Fullpath #| %{"$_," + $date}
$rptinsert = #()
for ($i=0; $i -lt ($content.Count); $i++)
{
if ($i -eq 0)
{
$rptinsert += $content[$i] + ",""ReportDate"""
}
else
{
$rptinsert += $content[$i] + ",`"$date`""
}
}
$Report = $Path + $file.PSChildName.Substring(0, 10) + "-FileSizes2.csv"
$rptinsert | Export-Csv -path $Report -Encoding ascii -NoTypeInformation
}
I'm sure there are shorter methods to perform the some of my lines as well, just not looking for that right now. ;-)
To use Export-Csv the way you are expecting, you need to be inputting objects with property/value pairs. You are piping in strings. The only property a string has is Length. I would use Import-Csv to read the files, modify the returned values, and then Export-Csv to output the changed objects. Below is a blueprint that will work:
$Path = "C:\temp\"
$files = Get-ChildItem $Path -filter '*.csv'
Foreach ($file in $files) {
$datetmp = $file.Name.Substring(0,10).Split('_')
$date = $datetmp[1],$datetmp[2],$datetmp[0] -join '/'
$content = Import-Csv $file | Add-Member -MemberType NoteProperty -Name 'ReportDate' -Value $date -PassThru
$content | Export-Csv -Path ($Path + $file.Name.Substring(0, 10) + "-FileSizes2.csv") -NoType
}
The output of Import-Csv is a collection of custom objects with property names that match the header line of the CSV file. Since it appears you want the same value added to every line of a CSV file, you can just run one Add-Member command. If each line needs a different value, then you will need to loop through each line and run an Add-Member command.
Add-Member allows for adding different member types to an object. In your case, you want to add a NoteProperty type with a value.
Once the updates are complete to one CSV's contents, you can pipe those results into Export-Csv. -NoType prevents an additional header line with type information from the output.
I have many file in a folder, I would like to check the existing and matching of the file with variable that I initialize. Then, if the file exit and match, I want to get some information from the files (many file), then create a new file depend on how many file exist and match.
I tried this code, I can check the matching and existing file. I can create a new file and get the information from the file, but I only can create 1 file.
The information that I get from the file, each file is different.
$ID = "123"
$Pre = "ABC"
$Path = "C:\Folder"
$PO = Get-ChildItem -Path $Path
foreach ($File in $PO) {
if (($File.Name -match $ID) -and ($File.Name -match $Pre)) {
Write-Host ">>POfile Found: $File"
} else {
Write-Host ">>Check Again!"
}
}
# CREATE FILE
$Jb_Path = "C:\Folder\Jb"
## GET INFORMATION
$count = 1
$Get_PO = Get-ChildItem -Path $Path\$File -File -Recurse
$POfile = Get-Random -InputObject $Get_PO -Count $count
Write-Host ">>Selected POfile= $POfile"
$FilteredContents = Get-Content $POfile | Where-Object {$_ -like "*;INFO*"}
$Get_INFO = $FilteredContents.Substring(5,2)
## NEW FILE
New-Item -Path $Jb_Path\NEW_$Pre$ID-$Get_INFO.txt -Force
In the section # CREATE FILE you are referencing the variable $File which has the last value iterated in the previous foreach (even if it didn't match the if condition).
Asuming the $Pre is for prefix and comes first in a file name simply do a
Get-ChildItem "$Path\*$Pre*$ID*"
to only get file names for your criteria.
As $File contains only one file name a Get-Random doesn't make sense, especially as it might not contain a line with ;INFO
Assuming the two characters to extract are in front of ;INFO this untested script might do:
$Pre = "ABC"
$ID = "123"
$Path = "C:\Folder"
$Jb_Path= "C:\Folder\Jb"
Get-ChildItem "$Path\*$Pre*$ID*" | Get-Content |
Select-String -Pattern '^.....(..).*;INFO' |
Get-Random | ForEach-Object {
$NewFile = Join-Path $Jb_Path ('NEW_{0}{1}-{2}.txt' -f $Pre,
$ID,$_.Matches.Groups[1].Value)
New-Item -Path $NewFile -ItemType File -Force -WhatIf
}
It will only output what it would do without the -WhatIf parameter.
If no file matching the criteria and RegEx pattern is found it will silently continue.
If my assumptions led me wrong, enhance your question be editing it with more details.