Get-Content piped with Add-Content - powershell

I encountered something weird I do not understand. My scenario:
I have in C:\Functions multiple .ps1 files. I would like to copy the content of the files to one file (AllFunctions.ps1). The file CopyFunctions2AllFunctions.ps1 is the file that execudes my commands.
$path="C:\Functions\*.ps1"
$destination="C:\Functions\AllFunctions.ps1"
Clear-Content -Path C:\Functions\AllFunctions.ps1
Get-Content -Path $path -Exclude "C:\Functions\CopyFunctions2AllFunctions.ps1" | Add-Content -Path $destination
The error message is in german, however, it says AllFunctions.ps1 cannot be accessed, because it is used in another process.
The code works if replace
$path="C:\Functions\*.ps1"
with a specific file name like
$path="C:\Functions\Read-Date.ps1"
-Force didnt help
Also, the code worked until Add-Content -Path $destination. When I executed Get-Content... the terminal didnt show me just what was inside the .ps1 files, but also the content of the terminal, with all the errors I encountered while trying...
Does someone have an idea?

There are 2 things to be fixed in this code, first the new code:
$path="C:\Functions"
$destination="C:\Functions\AllFunctions.ps1"
Clear-Content -Path C:\Functions\AllFunctions.ps1
$functions=Get-ChildItem -Path $path -Exclude CopyFunctions2Profile.ps1 | Get-Content
Add-Content -Path $destination -Value $functions
Issue #1
$path="C:\Functions\*.ps1" doesnt work, PS is also copying the content of the terminal, I dont know why...Therefore, we dont use wildcards in our $path.
Because of that we need to use Get-Childitem in the code as the following:
$functions=Get-ChildItem -Path $path -Exclude CopyFunctions2Profile.ps1 | Get-Content
Issue #2
Working with pipes, PS processes one item and sends it through the pipe, then the second and so on. Due to that, when item 2 is sent to Add-Content, "AllFunctions.ps1" is still being used for item 1.
Therefore, we need to save our Get-Content in a variable ($functions) and then use it in Add-Content.

Related

Is it possible to "-passthru" to Log file only and not the console when using "Start-Transcript -Path "$LogOutput"

I have a Powershell script where I want the console to output my custom messages only, but I would like to capture what the command is doing in a log only. Is this possible?
Just to make it clearer with an example below. I want to copy all the Sub Directories and Files as they are in their own directory to a new location:
Start-Transcript -Path "$LogOutput" -IncludeInvocationHeader -Append
Get-ChildItem -Path "$Source" | Copy-Item -Destination "$Destination" -Exclude "File*.xml" -Force -Recurse -PassThru
Stop-Transcript
I then use $? to get the success of the result on the console for my custom messages.
The above shows details I find helpful but it outputs the -PassThru on the console which I do not want to display there. If I don't specify it, it outputs nothing in the Transcript log either.
If I try appending to the copy command ...-PassThru | Out-File -FilePath "$LogOutput" -Append (The same Log used for Transcript) it fails as the log file is locked by the Transcript. Is there a way to make this possible, or will I have to append ...-PassThru | Out-File -FilePath "$LogOutput" -Append to all my commands individually?
Many thanks in advance.

Copying files to specific folder declared in a CSV file using Powershell Script

i am quite new to powershell and i am trying to make a script that copy files to certain folders that are declared in a CSV file. But till now i am getting errors from everywhere and can't find nothing to resolve this issue.
I have this folders and .txt files created in the same folder as the script.
Till now i could only do this:
$files = Import-Csv .\files.csv
$files
foreach ($file in $files) {
$name = $file.name
$final = $file.destination
Copy-Item $name -Destination $final
}
This is my CSV
name;destination
file1.txt;folderX
file2.txt;folderY
file3.txt;folderZ
As the comments indicate, if you are not using default system delimiters, you should make sure to specify them.
I also recommend typically to use quotes for your csv to ensure no problems with accidentally including an entry that includes the delimiter in the name.
#"
"taco1.txt";"C:\temp\taco2;.txt"
"# | ConvertFrom-CSV -Delimiter ';' -Header #('file','destination')
will output
file destination
---- -----------
taco1.txt C:\temp\taco2;.txt
The quotes make sure the values are correctly interpreted. And yes... you can name a file foobar;test..txt. Never underestimate what users might do. 😁
If you take the command Get-ChildItem | Select-Object BaseName,Directory | ConvertTo-CSV -NoTypeInformation and review the output, you should see it quoted like this.
Sourcing Your File List
One last tip. Most of the time I've come across a CSV for file input lists a CSV hasn't been needed. Consider looking at grabbing the files you in your script itself.
For example, if you have a folder and need to filter the list down, you can do this on the fly very easily in PowerShell by using Get-ChildItem.
For example:
$Directory = 'C:\temp'
$Destination = $ENV:TEMP
Get-ChildItem -Path $Directory -Filter *.txt -Recurse | Copy-Item -Destination $Destination
If you need to have more granular matching control, consider using the Where-Object cmdlet and doing something like this:
Get-ChildItem -Path $Directory -Filter *.txt -Recurse | Where-Object Name -match '(taco)|(burrito)' | Copy-Item -Destination $Destination
Often you'll find that you can easily use this type of filtering to keep CSV and input files out of the solution.
example
Using techniques like this, you might be able to get files from 2 directories, filter the match, and copy all in a short statement like this:
Get-ChildItem -Path 'C:\temp' -Filter '*.xlsx' -Recurse | Where-Object Name -match 'taco' | Copy-Item -Destination $ENV:TEMP -Verbose
Hope that gives you some other ideas! Welcome to Stack Overflow. 👋

Create PS script to find files

I want to start by saying coding is a bit outside of my skill set but because a certain problem keeps appearing at work, I'm trying to automate a solution.
I use the below script to read an input file for a list of name, search the C:\ for those files, then write the path to an output file if any are found.
foreach($line in Get-Content C:\temp\InPutfile.txt) {
if($line -match $regex){
gci -Path "C:\" -recurse -Filter $line -ErrorAction SilentlyContinue |
Out-File -Append c:\temp\ResultsFindFile.txt
}
}
I would like to make two modifications to this. First, to search all drives connected to the computer not just C:\. Next, be able to delete any found files. I'm using the Remove-Item -confirm command but so far can't make it delete the file it just found.

Search computer for .docx, .xls files using PowerShell

I am new to PowerShell and having difficulties trying to locate certain types of files (.doc, .docx, .xls, .xlsx), output the filenames and sizes (in groups by file extension) to a text file, and also include the total number files and total files size for each file extension.
The code that I have so far is:
$Report_File_Destination = "C:\Users\StayPositibve\Desktop\testing20.txt"
$path = ".\*"
Get-ChildItem $path -Include *.doc, *.docx, *.xls, *.xlsx -Recurse | Group-Object Extension -NoElement | Out-File $Report_File_Destination -Append
Every time I run this code, I receive a Get-ChildItem Access is Denied (I am running PowerShell as Administrator). What am I doing wrong? Thanks for your help!
This is due to the fact that it exists some paths that your are not allowed to browse. You can try to use -ErrorAction Ignore -Force options of Get-ChildItem to ignore these errors or force access to files that cannot otherwise be accessed by the user, such as hidden or system files. in old version of PowerShell you can test -ErrorAction SilentlyContinue.
Get-ChildItem $path -Include *.doc, *.docx, *.xls, *.xlsx -Recurse -ErrorAction Ignore -Force

How to move a file to another directory and change the content of it using pipe in one line in Powershell?

Below code does not work. But doing them seperately in two line works.
Move-Item file.txt \same-directory | Set-Content -Path \same-directoy -Value "New content"
The Move-Item cmdlet without switch -PassThru returns nothing, so in that case, nothing gets sent through the pipe to the Set-Content cmdlet.
If you really want to do this as one-liner, use
Move-Item -Path 'D:\file.txt' -Destination 'D:\some-directory' -PassThru | Set-Content -Value "New content"
Since now we're actually piping the moved object, the -Path parameter for the Set-Content needs to be omitted.
Of course, the destination folder D:\some-directory needs to exist