How to list file and folder names in powershell? - powershell

I want to write all files and folders' names into a .gitignore file like the below:
Folder1
Folder2
File1.bar
File2.foo
and so on.
The writing part can be achieved with the Out-File command, but I'm stuck in printing those names like the format above.
I'm aware of the command Get-ChildItem but it prints out a bunch of metadata like dates and icons too which are useless for the matter. btw, I'm looking for a single-line command, not a script.

Just print the Name property of the files
$ (ls).Name >.gitignore
$ (Get-ChildItem).Name | Out-File .gitignore

I'm aware of the command Get-ChildItem but it prints out a bunch of metadata like dates and icons [...]
That's because PowerShell cmdlets output complex objects rather than raw strings. The metadata you're seeing for a file is all attached to a FileInfo object that describes the underlying file system entry.
To get only the names, simply reference the Name property of each. For this, you can use the ForEach-Object cmdlet:
# Enumerate all the files and folders
$fileSystemItems = Get-ChildItem some\root\path -Recurse |Where-Object Name -ne .gitignore
# Grab only their names
$fileSystemNames = $fileSystemItems |ForEach-Object Name
# Write to .gitignore (beware git usually expects ascii or utf8-encoded configs)
$fileSystemNames |Out-File -LiteralPath .gitignore -Encoding ascii

Would this do?
(get-childitem -Path .\ | select name).name | Out-File .gitignore

Related

Copying a document into a folder and then renaming it with part of the folder name

I have a large set of folders in Windows named like this:
firstname lastname_xxxxxxx_
where xxxxxxx is a numeric ID.
All these sub-folders are in a folder called "T:\Tests2022"
The directories look like this:
John Smith_12345678_
Mary Scott_87945687_
William Tell_9875348_
Jane Doe_57982388_
e.g. a complete path is T:\Tests2022\John Smith_12345678_
I have a document "testscript.txt" that I want to move into each of these folders. This file also sits in the root of "Tests2022" (i.e. T:\Tests2022\testscript.txt)
However, I would like to prepend "Firstname_" to the file. (e.g. in the first folder the file would be called "T:\Tests2022\John Smith_12345678_\John_testscript.txt").
Ideally, if the world were perfect, the file would be named "john Smith_tescript.txt")
Simply moving the file in the CMD line is easy: e.g. 'Moveit.bat' contains
for /D %%a in (".\*.*") do xcopy /y /d ".\testscript.txt" "%%a\"
I could do this manually, but I have to do something similar every two weeks with a different list of test directories so that a macro would be ideal.
I need help to move this to PowerShell and then use PowerShell to parse and collect text either to the first space (between the firstname/lastname pair) or the first underscore.
Inline comments should help to understand the logic. If you want to learn something new you should look for yourself the commands being used in the script.
This link https://regex101.com/r/h0SYVz/1 should explain this:
$_.Name -replace '(?<=_).+'
$targetFile = 'T:\Tests2022\testscript.txt'
# Enumerate all Directories in Test2022
Get-ChildItem T:\Tests2022\ -Directory | ForEach-Object {
# if this Subdirectory has the `testscript.txt` in it
if($_ | Get-ChildItem -Filter *testscript.txt) {
# go to the next Directory, nothing to do here
return
}
# if this Subdirectory doesn't have the file,
# extract everything up until the underscore for the folder name
# and concatenate with `testscript.txt`
$name = ($_.Name -replace '(?<=_).+') + 'testscript.txt'
# Join this folder's absolute path with the new file name
$destination = Join-Path $_.FullName -ChildPath $name
# now we can copy the `.txt` file into this folder
Copy-Item $targetFile -Destination $destination
}

How to get Foldername into the output txt file of Using Out-File or ">" in Powershell?

I am doing a command line approach for making a filename content into txt file.
Here's what I've got right now.
I have got the dir command to get the names and exclude the .txt files in the folder I want to output. I was able to sort files by name using the sort-object command. And the out-file I've written down there is just to open up what I'm doing right now.
dir -n -exclude *.txt | sort-object | out-file -confirm .\<current foldername>.txt
However I want this command line to output it's unique foldername as in lets say an address is "..\folder\" & "..\folder2\" and I want to use out-file or > command in such a way that it creates folder.txt and folder2.txt, on different and multiple filetypes. Mind you I'm not talking about "filepath" for .txt filename.
Try this:
dir -n -Exclude *.txt |Sort-Object|Out-File -Confirm "$((Get-Item .).Name).txt"
Between the "" the filename is constructed. This is what happens:
The "" indicate it is a string
Within a string it is possible to embed an expression
The expression that is embedded here is (Get-Item .).Name that gets the name of the current directory (.)
To embed code in a string you have to format like this: $(<embedded code block>)
After the embedded code the string literal .txt is added

Combine TXT files in a directory to one file with column added at end with for file name

I have got a set of txt files in a directory that I want to merge together.
The contents of all the txt files are in the same format as follows:
IPAddress Description DNSDomain
--------- ----------- ---------
{192.168.1.2} Microsoft Hyper-V Network Adapter
{192.168.1.30} Microsoft Hyper-V Network Adapter #2
I have the below code that combines all the txt files in to one txt file called all.txt.
copy *.txt all.txt
From this all.txt I can't see what lines came from what txt file. Any ideas on any bits of code that would add an extra column to the end txt file with the file name the rows come from?
As per the comments above, you've put the output of Format-Table into a text file. Note that Format-Table might be visually structured on screen, but is just lines of text. By doing that you have made it harder to work with the data.
If you just want a few properties from the results of the Get-WMIObject cmdlet, use Select-Object which (in the use given here) will effectively filter the data for just the properties you want.
Instead of writing text to a simple file, you can preserve the tabular nature of the data by writing to a structured file (i.e. CSV):
Get-WmiObject -Class Win32_NetworkAdapterConfiguration -Filter IPEnabled=TRUE -ComputerName SERVERNAMEHERE |
Select-Object PSComputerName, IPAddress, Description, DNSDomain |
Export-Csv 'C:\temp\server.csv'
Note that we were able to include the PScomputerName property in each line of data, effectively giving you the extra column of data you wanted.
So much for getting the raw data. One way you could read in all the CSV data and write it out again might look like this:
Get-ChildItem *.csv -Exclude all.csv |
Foreach-Object {Import-Csv $_} |
Export-Csv all.csv
Note that we exclude the output file in the initial cmdlet to avoid reading and writing form/to the same file endlessly.
If you don't have the luxury to collect the data again you'll need to spool the files together. Spooling files together is done with Get-Content, something like this:
Get-ChildItem *.txt -Exclude all.txt |
Foreach-Object {Get-Content $_ -Raw} |
Out-File all.txt
In your case, you wanted to suffix each line, which tricker as you need to process the files line-by-line:
$files = Get-ChildItem *.txt
foreach($file in $files) {
$lines = Get-Content $file
foreach($line in $lines) {
"$line $($file.Name)" | Out-File all.txt -Append
}
}

Need to create a script that scans for file names, generates a template for each file and inserts filename into 2 spots within template

Basically what I need is a way to scan a folder for certain files (let's say anything with .xls/xlsx) and generate a text file for each one of those files with a template layout. I figured out how to do this with the script below. However, I need it also to place the filename within the template file as well in 2 locations.
Here is how I have it now.
Get-ChildItem "*PATH*" | Foreach-Object {$_.Name} > C:\Temp\TextGenerate\FileNames.txt
Get-Content C:\Temp\TextGenerate\FileNames.txt | ForEach-Object {
Copy-Item -Path C:\Temp\TextGenerate\FileTemplate.txt -Destination ("C:\Temp\TextGenerate\ListFiles\{0}.txt" -f $_)
}
Basically it scans the folder location, creates a text file (FileNames.txt) with all the file names using a file template file (FileTemplate.txt) and creates one for each file name.
This template (FileTemplate.txt) would be like this:
REPORT-ID=TEST FILE=\\XXXXXXXXXX\XXXXXXXXXX\XXXXXXXXXXX\*insert filename here*, TYPE=XLSX, "SECTION=TEST" TOPIC-ID=TOPIC1, "TOPIC-ITEM=*insert filename here*"
Output would need to be:
REPORT-ID=TEST FILE=\\XXXXXXXXXX\XXXXXXXXXX\XXXXXXXXXXX\filename1.xlsx, TYPE=XLSX, "SECTION=TEST" TOPIC-ID=TOPIC1, "TOPIC-ITEM=filename1.xlsx"
and so on.
Everything on the template would always be the same the only thing that would need to change for each file generated would be the filename for each file found in the folder in the *insert filename here* location.
I am having a problem understand how to insert such things into the file. I would also like if possible to insert the data modified into another line of text in the generated template if possible.
As JosefZ already suggested: read the template file just once, then create the files by filling the template string with values and writing the modified string to the output files.
I would, however, recommend modifying the template to allow using the format operator (-f) on it:
REPORT-ID=TEST FILE=\\XXXXXXXXXX\XXXXXXXXXX\XXXXXXXXXXX\{0}, TYPE=XLSX, "SECTION=TEST" TOPIC-ID=TOPIC1, "TOPIC-ITEM={0}"
Also, there's no need to write the names to a file first. Change your code to something like this:
$template = Get-Content 'C:\Temp\TextGenerate\FileTemplate.txt' | Out-String
Get-ChildItem "*PATH*" | Select-Object -Expand Name | ForEach-Object {
$path = "C:\Temp\TextGenerate\ListFiles\{0}.txt" -f $_
$content = $template -f $_
Set-Content -Path $path -Value $content
}

Get Relative paths of all the folders, sub-folders and files in a folder

I have a folder named source. It's structure is like the following.
source\a.jpg
source\b.jpg
source\c.xml
source\d.ps1
source\subdir1\a.xml
source\subdir2\b.png
source\subdir3\subsubdir1\nothing.img
I want to list all the relative paths of folders, sub-folders and files in a text file say, out.txt. For above the output I expect is:
source\a.jpg
source\b.jpg
source\c.xml
source\d.ps1
source\subdir1\a.xml
source\subdir2\b.png
source\subdir3\subsubdir1\nothing.img
source\subdir1
source\subdir2
source\subdir3
source\subdir3\subsubdir1
You can see that the output includes individual folders and sub-folders too.
Note: I am in a folder just outside the source folder. I mean for example I am in fold folder which contains source folder -> fold/source but if your solution includes putting the script inside the source folder, thats fine too. Both solutions are fine. This may be easy but I am not familiar with powershell but can at least run scripts from it if given.
EDIT1: Okay, in the "duplicate question" the answer is for relative paths of individual files. But I also want the folders and sub-folders.
EDIT2: Okay, I wrote a command:
(gci -path source -recurse *.|Resolve-path -relative) -replace "","" | out-file -FilePath output.txt -Encoding ascii
Now, this command gives me the relative name of only subdirectory inside the source(in the actual source folder of mine with a different name; source is a dummy name obviously!). What should I change in this code to get other names of files inside the subdirectory in source.
This is clean one line answer,no loops on my part to write, which does the job perfectly. I produced it by luck "playing around" a bit.
(gci -Path source -Recurse *.*|Resolve-Path -Relative) -replace "\.","" |
Out-File -FilePath output.txt -Encoding ascii
Not very clean but this might be an option.
(Get-ChildItem -Recurse -Path "C:\ABC\source\").FullName|ForEach{[Regex]::Replace($_,'^C:\\ABC\\','')}
I would probably do something like this:
$source = 'C:\path\to\source'
$parent = [IO.Path]::GetDirectoryName($source) -replace '\\+$'
$pattern = '^' + [regex]::Escape($parent) + '\\'
Get-ChildItem -Path $source -Recurse | % { $_.FullName -replace $pattern }