In a directory there will be 2 type of files with same name but different extension for eg:1.png , 1.txt, test_76.png,test_76.txt, test_70.png. In this case test_70.png dosent have its .txt counterpart.I am using this code
$scL = dir *.txt | select Basename
$SList = #($scL -notmatch "MICRO")
$pList = dir *.png | select Basename
$PList = #($pList -notmatch "MICRO")
Compare-Object $PList $SList | ForEach-Object {$_.InputObject} | out-file result.txt
but i am unable to get the desired output that is test_70.png in the output file.Also i want to wrap the output inside the text file in double quotes i.e; the outfile should contain entry like this "test_70.png". Can anyone throw light on what am i missing in the compare-object cmdlet.
Your InputObject is a file object so you will need to access the name. Also in Powershell you can access the properties of the the items in a collection directly. Something like this:
(Compare-Object $PList $SList).InputObject.Name | % {"`"$_`""} | Out-File result.txt
Related
Sorry in advance for the probably trivial question, I'm a powershell noob, please bear with me and give me advice on how to get better.
I want to achieve a file index index.txt that contains the list of all files in current dir and subdirs in this format:
./dir1/file1.txt 07.05.2020 16:16 1959281
where
dirs listed are relative (i.e. this will be run remotely and to save space, the relative path is good enough)
the delimiter is a tab \t
the date format is day.month.fullyear hours:minutes:seconds, last written (this is the case for me, but I'm guessing this would be different on system setting and should be enforced)
(the last number is the size in bytes)
I almost get there using this command in powershell (maybe that's useful to someone else as well):
get-childitem . -recurse | select fullname,LastWriteTime,Length | Out-File index.txt
with this result
FullName LastWriteTime Length
-------- ------------- ------
C:\Users\user1\Downloads\test\asdf.txt 07.05.2020 16:19:29 1490
C:\Users\user1\Downloads\test\dirtree.txt 07.05.2020 16:08:44 0
C:\Users\user1\Downloads\test\index.txt 07.05.2020 16:29:01 0
C:\Users\user1\Downloads\test\test.txt 07.05.2020 16:01:23 814
C:\Users\user1\Downloads\test\text2.txt 07.05.2020 15:55:45 1346
So the questions that remain are: How to...
get rid of the headers?
enforce this date format?
tab delimit everything?
get control of what newline character is used (\n or \r or both)?
Another approach could be this:
$StartDirectory = Get-Location
Get-ChildItem -Path $StartDirectory -recurse |
Select-Object -Property #{Name='RelPath';Expression={$_.FullName.toString() -replace [REGEX]::Escape($StartDirectory.ToString()),'.'}},
#{Name='LastWriteTime';Expression={$_.LastWriteTime.toString('dd.MM.yyyy HH:mm:ss')}},
Length |
Export-Csv -Path Result.csv -NoTypeInformation -Delimiter "`t"
I recommend to use proper CSV files if you have structured data like this. The resulting CSV file will be saved in the current working directory.
If the path you are running this from is NOT the current scrip path, do:
$path = 'D:\Downloads' # 'X:\SomeFolder\SomeWhere'
Set-Location $path
first.
Next, this ought to do it:
Get-ChildItem . -Recurse -File | ForEach-Object {
"{0}`t{1:dd.MM.yyyy HH:mm}`t{2}" -f ($_ | Resolve-Path -Relative), $_.LastWriteTime, $_.Length
} | Out-File 'index.txt'
On Windows the newline will be \r\n (CRLF)
If you want control over that, this should do:
$newline = "`n" # for example
# capture the lines as string array in variable $lines
$lines = Get-ChildItem . -Recurse -File | ForEach-Object {
"{0}`t{1:dd.MM.yyyy HH:mm}`t{2}" -f ($_ | Resolve-Path -Relative), $_.LastWriteTime, $_.Length
}
# join the array with the chosen newline and save to file
$lines -join $newline | Out-File 'index.txt' -NoNewline
Because your requirement is to NOT have column headers in the output file, I'm using Out-File here instead of Export-Csv
I have a directory on a server called 'servername'. In that directory, I have subdirectories whose name is a date. In those date directories, I have about 150 .csv file audit logs.
I have a partially working script that starts from inside the date directory, enumerates and loops through the .csv's and searches for a string in a column. Im trying to get it to export the row for each match then go on to the next file.
$files = Get-ChildItem '\\servername\volume\dir1\audit\serverbeingaudited\20180525'
ForEach ($file in $files) {
$Result = If (import-csv $file.FullName | Where {$_.'path/from' -like "*01May18.xlsx*"})
{
$result | Export-CSV -Path c:\temp\output.csv -Append}
}
What I am doing is searching the 'path\from' column for a string - like a file name. The column contains data that is always some form of \folder\folder\folder\filename.xls. I am searching for a specific filename and for all instances of that file name in that column in that file.
My issue is getting that row exported - export.csv is always empty. Id also like to start a directory 'up' and go through each date directory, parse, export, then go on to the next directory and files.
If I break it down to just one file and get it out of the IF it seems to give me a result so I think im getting something wrong in the IF or For-each but apparently thats above my paygrade - cant figure it out....
Thanks in advance for any assistance,
RichardX
The issue is your If block, when you say $Result = If () {$Result | ...} you are saying that the new $Result is equal what's returned from the if statement. Since $Result hasn't been defined yet, this is $Result = If () {$null | ...} which is why you are getting a blank line.
The If block isn't even needed. you filter your csv with Where-Object already, just keep passing those objects down the pipeline to the export.
Since it sounds like you are just running this against all the child folders of the parent, sounds like you could just use the -Recurse parameter of Get-ChildItem
Get-ChildItem '\\servername\volume\dir1\audit\serverbeingaudited\' -Recurse |
ForEach-Object {
Import-csv $_.FullName |
Where-Object {$_.'path/from' -like "*01May18.xlsx*"}
} | Export-CSV -Path c:\temp\output.csv
(I used a ForEach-Object loop rather than foreach just demonstrate objects being passed down the pipeline in another way)
Edit: Removed append per Bill_Stewart's suggestion. Will write out all entries for the the recursed folders in the run. Will overwrite on next run.
I don't see a need for appending the CSV file? How about:
Get-ChildItem '\\servername\volume\dir1\audit\serverbeingaudited\20180525' | ForEach-Object {
Import-Csv $_.FullName | Where-Object { $_.'path/from' -like '*01May18.xlsx*' }
} | Export-Csv 'C:\Temp\Output.csv' -NoTypeInformation
Assuming your CSVs are in the same format and that your search text is not likely to be present in any other columns you could use a Select-String instead of Import-Csv. So instead of converting string to object and back to string again, you can just process as strings. You would need to add an additional line to fake the header row, something like this:
$files = Get-ChildItem '\\servername\volume\dir1\audit\serverbeingaudited\20180525'
$result = #()
$result += Get-Content $files[0] -TotalCount 1
$result += ($files | Select-String -Pattern '01May18\.xlsx').Line
$result | Out-File 'c:\temp\output.csv'
I have 2 folders: 'Old' and 'New'. Most of the files from 'Old' have been copied to 'New'. However, the structure of the sub-folders in 'Old' and 'New" are different. So the file-path for a file in 'Old' is very different from its copy in 'New'.
I need to loop through each file in 'Old', search for that file in 'New', and write the old and new file-paths for each file to a text file.
I have been assigned to do this manually, but it will take a long time due to the number of files. So I want to write a script. I am new to Powershell and am having difficulty figuring out which cmdlets can help me with my task.
I will appreciate any kind of guidance. Thank you.
try Something like this
#list old files
$patholdfile="c:\temp"
$listoldfile=Get-ChildItem $patholdfile -File -Recurse | select Name, FullName
#list new files
$pathnewfile="c:\temp2"
$listnewfile=Get-ChildItem $pathnewfile -File -Recurse | select Name, FullName
#extract liste file old and name and search all file in newlist
$resultsearch=#()
foreach ($currentfile in $listoldfile)
{
$resultsearch+=New-Object psobject -Property #{
Name=$currentfile.Name
OldPath=$currentfile.FullName
#if you want the firt founded uncomment this and comment after
#NewPaths=($listnewfile | Where {$_.Name -eq $currentfile.Name} | select FullName -First 1).FullName
NewPaths=($listnewfile | Where {$_.Name -eq $currentfile.Name} | select FullName).FullName -join "~"
}
}
#export result in csv file
$resultsearch | select name, OldPath , NewPaths | export-csv -Path "c:\temp\result.txt" -NoTypeInformation
What am I doing wrong?
I want to create a new text file containing IP Addresses from a text file containing only Hostnames.
function Get-HostToIP($hostname) {
$result = [system.Net.Dns]::GetHostByName($hostname)
$result.AddressList | ForEach-Object {$_.IPAddressToString }
}
Get-Content "hostnames.txt" | ForEach-Object {(Get-HostToIP($_)) >> ip.txt}
By default, Powershell is looking under C:\windows\system32 folder for the files. Replace the file names with full path of the files and it should work:
Get-Content "C:\path\to\hostnames.txt" | ForEach-Object {(Get-HostToIP($_)) >> c:\path\to\ip.txt}
I am trying to use powershell to get all child elements in a folder the code I am using is
Get-ChildItem -Recurse -path C:\clntfiles
this code gives output like
Mode LastWriteTime Length Name
---- ------------- ------ ----
-a--- 4/29/2015 9:11 AM 6919044 HD 100616 Dec2014.pdf
-a--- 5/1/2015 11:42 AM 7091019 HD 101642 Jan2015.pdf
I don't want Mode lastWriteTime Length and name of file without .pdf extension
the output should be like
Dec2014
Jan2015
I am not sure how to filter that. please advise
I'll start by posting something similar to Leptonator's answer, but simplified by using the Select-Object command (alias Select used in code because it's habit, and I'm lazy).
$files = Get-ChildItem -Recurse -path C:\clntfiles | Select -ExpandProperty BaseName
Now that gets you the file names without extension. But, you actually asked for only part of the file names, as the first file name is "HD 100616 Dec2014.pdf" and you specified that you actually only want "Dec2014" to be returned. We can do that a couple different ways, but my favorite of them would be a RegEx match (because RegEx is awesome, and I think the LastIndexOf/SubString combo is overly complicated imho).
So, a RegEx match of "\w+$" will get what you want. That is broken down like this:
\w means any letter or number
+ means 1 or more of them
$ means the end of the string/line
So that's 1 or more alpha-numeric characters at the end of the string. We pipe our array of file names into a ForEach-Object loop (alias ForEach used out of habit), and then we have:
$Files | ForEach{ [RegEx]::Matches($_,"\w+$")}
Now, this outputs a [System.Text.RegularExpressions.Match] object, which is more than you want, but it does have a property Value which is exactly what you asked for! So we use Select -Expand again for that property and the output is precisely what you asked for:
$files = Get-ChildItem -Recurse -path C:\clntfiles | Select -ExpandProperty BaseName
$files | ForEach{[regex]::Matches($_,"\w+$")} | Select -Expand Value
RegEx matches are really handy, and if you learn about them you can simplify that quite a bit more like this:
gci C:\clntfiles -Rec | ?{$_.BaseName -match "(\w+)$"} | %{$Matches[1]}
That one line, as well as the two line code above it both should output:
Dec2014
Jan2015
Something like this should do it for you..
$files = Get-ChildItem -Recurse -path C:\clntfiles
if ($files -ne $null)
{
foreach ($file in $files)
{
$file.BaseName
}
}
In my folder, it shows:
> 2014-03-28_exeresult_file
> 2014-03-30_exeresult_file
> 2014-03-31_exeresult_file
> 2014-04-02_exeresult_file
> 2014-04-03_exeresult_file
> 2014-04-04_exeresult_file
> 2014-04-06_exeresult_file
> 2014-04-08_exeresult_file
and are indeed .txt files
Hope this helps!
Use the following Get-ChildItem -Recurse -name -path C:\clntfiles. This will get you only the file names.
Working solution:
$names = Get-ChildItem -name
foreach($n in $names) {$n.Substring(0,$n.IndexOf("."))}
You can also use LastIndexOf if part of the file name is .