Export Variable contents to file - powershell

I have contents in a variable from GitHub and I want to export then to file automatically created o my local machine
I have tried to use
$FileContent | Out-File ('C:\Devjobs\clonefolder' + '\' + $repo.name + '\' + $srccontent.name)
It gives the error
Out-File : Could not find a part of the path 'C:\Devjobs\clonefolder\bct-common-devcomm-codegen-messages\BCT.Common.DevComm.CodeGen.Messages.sln'.
At line:1 char:18
+ ... lnContent | Out-File ('C:\Devjobs\clonefolder' + '\' + $repo.name + ' ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : OpenError: (:) [Out-File], DirectoryNotFoundException
+ FullyQualifiedErrorId : FileOpenFailure,Microsoft.PowerShell.Commands.OutFileCommand

As stackprotector already commented, the error shows DirectoryNotFoundException, which means you are trying to create a file in a directory that does not yet exist.
To avoid that, first create the path for the output file, then create the file.
$pathOut = Join-Path -Path 'C:\Devjobs\clonefolder' -ChildPath $repo.name
# create the folder path if it does not exist already
$null = New-Item -Path $pathOut -ItemType Directory -Force
# now write the file
$FileContent | Set-Content -Path (Join-Path -Path $pathOut -ChildPath $srccontent.name)
By using the -Force switch on New-Item you will either create the directory, OR have a DirectoryInfo object returned if the folder already existed.
In this case, we have no further need for that object, so we discard it with $null =.
Beware that this only works like that on the file system, if you would do the same on a registry key, you wil lose all content of the existing key!
Note: I use Set-Content rather than Out-File because on PowerShell versions up to and including 5.1, Out-File without using the -Encoding parameter will write the file in Unicode (UTF16-LE) encoding which may or may not be what you expect.
Following your comment:
foreach ($srccontent in $srccontents) {
if (<cond>) {
$slnContent = <rest>
$NewslnContent = "content"
$pathOut = Join-Path -Path 'C:\Devjobs\clonefolder' -ChildPath $repo.name
# first create the folder path if it does not exist already
$null = New-Item -Path $pathOut -ItemType Directory -Force
# now write the file
$NewslnContent | Set-Content -Path (Join-Path -Path $pathOut -ChildPath $srccontent.name)
}
}

Instead of string concatenation you may want to try Join-Path for cross-platform. That being said, if you are on a Windows machine this is not likely to be your issue.
You may want to use Test-Path to verify if the path and the file exists already.
$path = 'C:' |
Join-Path -ChildPath 'Devjobs' |
Join-Path -ChildPath 'clonefolder' |
Join-Path -ChildPath $repo.name
$filepath = $path | Join-Path -ChildPath $srccontent.name
If (-Not (Test-Path $path)) {
New-Item -Type Directory -Path $path
}
If (-Not (Test-Path $filepath)) {
Remove-Item -Path $filepath
}
$FileContent | Out-File $filepath

Related

Rename files in a bulk from csv file in Powerhshell

Renaming files from a CSV
I am trying to write a script to reorganize files in a folder structure using csv as index file but I canĀ“t figure out in how to solve the Rename-Item error.
Questions
Is there others way to write this script in order to achieve the same results more easily?
How to pass the right parameters to Rename-Item?
My csv file template
folderName newName oldName
---------- ------- -------
01 Course Overview 01_Course_Overview 1280x720.mp4
02 Introduction to PowerShell 01_Introduction to PowerShell 1280x720 (1).mp4
02 Introduction to PowerShell 02_Who Is This Course For? 1280x720 (2).mp4
02 Introduction to PowerShell 03_What Is PowerShell? 1280x720 (3).mp4
02 Introduction to PowerShell 04_Windows PowerShell and PowerShell 7 1280x720 (4).mp4
PowerShell Script
$csv = Import-Csv '.\index.csv' -Delimiter ';'
$newFolders = $csv.folderName | Sort-Object -Unique
$listFolders = Get-ChildItem -Directory | Select-Object Name
$listFiles = Get-ChildItem | Where {$_.extension -eq ".mp4"}
ForEach ($a in $newFolders){
If ($listFolders.Name -contains $a){
Write-Host "The Folder $a exist"
}
else{
New-Item -Path $pwd.Path -Name $a -Type Directory | Out-Null
Write-Host "The folder $a has been created"
}
}
ForEach ($b in $csv){
If ($listFiles.Name -contains $b.oldName){
Write-Host "File $($b.oldName) exist"
Write-Host "Renaming file to: "$($b.newName)"
#Rename-Item $($b.oldName) -NewName $($b.newName)
#Write-Host "Moving file to: "$($b.folderName)"
#Move-Item .\$($b.newName) -Destination .\$($b.folderName)
}
else{
Write-Host "File $($b.oldName) doesn't exist" `n
}
}
Error when executin Rename-Item
No D:\Downloads\Pluralsight\_PowerShell_Essentials\01_Powershell_Getting_Started\Temp\indexfiles.ps1:30 caractere:9
+ Rename-Item $($b.oldName) -NewName $($b.newName)
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidArgument: (D:\Downloads\Pl...280x720 (2).mp4:String) [Rename-Item], ArgumentException
+ FullyQualifiedErrorId : RenameItemArgumentError,Microsoft.PowerShell.Commands.RenameItemCommand
Here you have an example of how this can be done, this is mainly a test case, it will create the files as you show us on the CSV and move them to the new folders based on the folderName column.
The code will look for the files on the current directory, before testing it with the real files, Set-Location (cd) to that folder.
If you're not sure if the code will work you can add a -WhatIf switch to Rename-Item and Move-Item.
Note, I have removed ? from the newName column since it's an invalid character on Windows. See this answer for more details.
# Go to a temporary folder for testing
Set-Location path/to/temporaryfolder/here
# Here you would use:
# $csv = Import-Csv path/to/csv.csv
$csv = #'
folderName newName oldName
01 Course Overview 01_Course_Overview 1280x720.mp4
02 Introduction to PowerShell 01_Introduction to PowerShell 1280x720 (1).mp4
02 Introduction to PowerShell 02_Who Is This Course For 1280x720 (2).mp4
02 Introduction to PowerShell 03_What Is PowerShell 1280x720 (3).mp4
02 Introduction to PowerShell 04_Windows PowerShell and PowerShell 7 1280x720 (4).mp4
'# -replace ' +',',' | ConvertFrom-Csv
# Create test files, this part is only for testing the code
$csv.foreach({ New-Item $_.oldName -ItemType File })
foreach($line in $csv)
{
if(-not (Test-Path $line.folderName))
{
# Create the Folder if it does not exist
New-Item $line.folderName -ItemType Directory -Verbose
}
Rename-Item -LiteralPath $line.oldName -NewName $line.newName
Move-Item -LiteralPath $line.newName -Destination $line.folderName
}
If I understand correctly, your real CSV file contains folder and/or file names with characters that are invalid like the ?.
To fix that, you can choose to remove those characters from the CSV file first, OR make sure you remove them before creating a folder or renaming a file.
For both options, you can use this small helper function:
function Remove-InvalidNameChars {
param(
[Parameter(Mandatory=$true, Position=0, ValueFromPipeline=$true, ValueFromPipelineByPropertyName=$true)]
[String]$Name,
[ValidateSet('File', 'Path')]
[string]$Type ='File'
)
if ($Type -eq 'File') {
$invalidChars = [IO.Path]::GetInvalidFileNameChars() -join ''
}
else {
$invalidChars = [IO.Path]::GetInvalidPathChars() -join ''
}
# build a regex string from the invalid characters
$removeThese = "[{0}]" -f [RegEx]::Escape($invalidChars)
# output the name with invalid characters removed
$Name -replace $removeThese
}
Method 1: remove the invalid characters from the CSV file and use cleaned-up data:
$sourcePath = 'D:\Test'
$csvFile = Join-Path -Path $sourcePath -ChildPath 'index.csv'
$csvData = Import-Csv -Path $csvFile -Delimiter ';'
foreach ($item in $csvData) {
$item.folderName = Remove-InvalidNameChars -Name $item.folderName -Type Path
$item.newName = Remove-InvalidNameChars -Name $item.newName -Type File
}
$csvData | Export-Csv -Path $csvFile -Delimiter ';' -Force # rewrite the CSV file if you like
# now use the cleaned-up data in $csvData for the rest of the code:
foreach ($item in $csvData) {
# create the output folder if this does not already exist
$targetPath = Join-Path -Path $sourcePath -ChildPath $item.folderName
$null = New-Item -Path $targetPath -ItemType Directory -Force
# move and rename the file if found
$sourceFile = Join-Path -Path $sourcePath -ChildPath $item.oldName
if (Test-Path -Path $sourceFile -PathType Leaf) {
$targetFile = Join-Path -Path $targetPath -ChildPath $item.newName
Move-Item -Path $sourceFile -Destination $targetFile
}
}
Method 2: leave the csv data as-is and make sure you remove invalid characters while renaming/moving:
$sourcePath = 'D:\Test'
$csvFile = Join-Path -Path $sourcePath -ChildPath 'index.csv'
$csvData = Import-Csv -Path $csvFile -Delimiter ';'
foreach ($item in $csvData) {
# create the output folder if this does not already exist
$targetPath = Join-Path -Path $sourcePath -ChildPath (Remove-InvalidNameChars -Name $item.folderName -Type Path)
$null = New-Item -Path $targetPath -ItemType Directory -Force
# move and rename the file if found
$sourceFile = Join-Path -Path $sourcePath -ChildPath (Remove-InvalidNameChars -Name $item.oldName -Type File)
if (Test-Path -Path $sourceFile -PathType Leaf) {
$targetFile = Join-Path -Path $targetPath -ChildPath (Remove-InvalidNameChars -Name $item.newName -Type File)
Move-Item -Path $sourceFile -Destination $targetFile
}
}
Note that Move-Item can move a file to a new destination and rename it at the same time, so you do not need Rename-Item
P.S. I noticed in your example CSV there are no extensions to the newName filenames..
If that is the case in real life, you need to add these aswell.
For that change the Move-Item line to:
Move-Item -Path $sourceFile -Destination ([IO.Path]::ChangeExtension($targetFile, [IO.Path]::GetExtension($sourceFile)))

PowerShell copy-item

I am trying to copy latest 30days files to the folder by this code:
$month = (get-date).AddDays(-30).ToString("yyyMM")
$lastmonthfiles = Write-Host (-join('DCP_', $month,"*.csv"))
Copy-Item -Path Write-Host (-join ("C:\DC+\History\", $lastmonthfiles)) -Destination C:\DC+\History\Backup
but I am having a problem in path in copy-item instruction, which is
Copy-Item : A positional parameter cannot be found that accepts argument 'C:\DC+\History\'.
At line:5 char:1
+ Copy-Item -Path Write-Host (-join ("C:\DC+\History\", $lastmonthfiles ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidArgument: (:) [Copy-Item], ParameterBindingException
+ FullyQualifiedErrorId : PositionalParameterNotFound,Microsoft.PowerShell.Commands.CopyItemCommand
I am new in PowerShell, and programming so, I could not understand, how can I update and achieve a goal.
Try this:
$Source = Get-Item "C:\Games"
$Destination = "E:\Backup"
$LogFile = "C:\Copy-LogFile.txt"
Copy-Item -Path $( $Source | Where LastWriteTime -LE (Get-Date).AddDays(-30) ) -Destination $Destination -Recurse -PassThru |
Out-File $LogFile -Force
This takes care of your copy function and generates an output log.
Sorry, but your code makes no sense to me...
If it is your aim to copy files to a subfolder in a backup path, try this:
# get the date to use as subfolder to copy to and also to filter the last 30 days files
$refDate = (Get-Date).AddDays(-30).Date # .Date sets it to midnight
# set this variable to the folder where the csv are to be found
$sourceFolder = 'X:\Path\To\Where\The\Files\Are'
# create a destination path to copy to (just a string)
$destination = Join-Path -Path 'C:\DC+\History\Backup' -ChildPath ($refDate.ToString("yyyMM"))
# create this destination folder
$null = New-Item -Path $destination -ItemType Directory -Force
# get the files and copy them to the destination folder
Get-ChildItem -Path $sourceFolder -Filter '*.csv' -File | # filter on CSV fies only
Where-Object { $_.LastWriteTime -ge $refDate } | # filter on date 'last 30 days'
Copy-Item -Destination $destination -Force

Powershell | Rename file with random name

I'm making a script to rename a specific file with a random name. But when running, the following error always occurs:
It is not possible to convert the value ".jpg" to the type "System.Int32". Error: "The input string was not in the correct format."
In C:\Windows\system32\WindowsPowerShell\v1.0\Modules\SetDiscordWallpaper\SetDiscordWallpaper.ps1:7 character:7
+ Rename-Item -Path $file.FullName -NewName ($random + $file.Exte ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidArgument: (:) [], RuntimeException
+ FullyQualifiedErrorId : InvalidCastFromStringToInteger
Here is the code I am using
function Set-DiscordWallpaper {
$path = "C:\Windows\Temp\*"
foreach($file in $(Get-ChildItem -Path $path -Include "Wallpaper.jpg")) {
$extension = [System.IO.Path]::GetExtension($file.FullName);
$randomName = [System.IO.Path]::ChangeExtension([System.IO.Path]::GetRandomFileName(), $extension)
$newPath = "C:\inetpub\wwwroot\"
Write-Host "Changing File $($file.Name) to $randomName"
Move-Item -Path $file.FullName -Destination $newPath
}
}
I ask you to help me please. I'm waiting the answer. Thanks
The code (second part in your question) creates the new random filename just fine, only the line Move-Item -Path $file.FullName -Destination $newPath does nothing with that new name and moves the file with its original name to the new path.
Change that line to
Move-Item -Path $file.FullName -Destination (Join-Path -Path $newPath -ChildPath $randomName)
so the file gets moved with the random name in the new path.
Or is your intention to copy the file to its new destination keeping the original filename there and after that rename the original?
In that case do:
Write-Host "Changing File $($file.Name) to $randomName"
Copy-Item -Path $file.FullName -Destination $newPath # copy with original name
$file | Rename-Item -NewName $randomName # rename the original file

Positional parameter cannot be found error in powershell

I am trying to append the date to a file name in my Powershell script but keep getting the following error (my code is below the error). Any help/direction would be greatly appreciated. Thank you.
Set-Content : A positional parameter cannot be found that accepts
argument '$null'.
At P:\CoverageVerifier\CombineTextFiles.ps1:8 char:50
+ ... thTrailer | Set-Content "${path}\\" + ${$dateStr} + "_CoverageVerifi ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidArgument: (:) [Set-Content], ParameterBindingException
+ FullyQualifiedErrorId : PositionalParameterNotFound,Microsoft.PowerShell.Commands.SetContentCommand
Here is my powershell code:
$path = "\\xx\\apps\\CoverageVerifier\\"
$pathHeader = "\\xx\\apps\\CoverageVerifier\\Header.txt"
$pathData = "\\xx\\apps\\CoverageVerifier\\Data.txt"
$pathTrailer = "\\xx\\apps\\CoverageVerifier\\Trailer.txt"
$date = Get-Date
$dateStr = $date.ToString("yyyyMMdd")
#Write-Output $dateStr
Get-Content $pathHeader,$pathData,$pathTrailer | Set-Content "${path}\\cvgver." + ${dateStr} + ".0101"
The first positional parameter of the Set-Content cmdlet is the -Path parameter.
Because of the way you define the paths for the files, it is bound to have problems with that.
As I understand, these are UNC paths, so try this instead:
# for LOCAL paths
# Set the driveletter to the actual drive you are using. For demo I'm using 'X:\'
# $path = 'X:\apps\CoverageVerifier'
# for UNC paths
# change 'servername' to your actual servers name
$path = '\\servername\apps\CoverageVerifier'
$pathHeader = Join-Path -Path $path -ChildPath 'Header.txt'
$pathData = Join-Path -Path $path -ChildPath 'Data.txt'
$pathTrailer = Join-Path -Path $path -ChildPath 'Trailer.txt'
$dateStr = (Get-Date).ToString("yyyyMMdd")
$outFile = Join-Path -Path $path -ChildPath ($dateStr + "_TestVerifier.txt")
Get-Content $pathHeader, $pathData, $pathTrailer | Set-Content $outFile
As you can see, I'm using the Join-Path cmdlet a lot to make sure my file paths get concatenated correctly.
Why don't you use the format operator and Join-Path?
Edit even with only one format
$path = "\\xx\apps\CoverageVerifier"
$pathHeader = Join-Path $path "Header.txt"
$pathData = Join-Path $path "Data.txt"
$pathTrailer = Join-Path $path "Trailer.txt"
Get-Content $pathHeader,$pathData,$pathTrailer |
Set-Content (Join-Path $path ("{0:yyyyMMdd}_TestVerifier.txt" -f (Get-Date))
you use set-content to modify the content of a file, not the filename:
https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.management/set-content?view=powershell-6

Error message in script

I am trying to script a solution copying some files from one location to another..
I have a list of files in a .csv format, with headers
"ParentFolder, Name, FullName, lastwritetime."
Content of file is, which has hundreds of lines, and different paths, but same drive letter:
"X:\clients\A90\201AA3.05\","2012.08 RAP Proposal.xlsm","X:\clients\A90\201AA3.05\2012.08 RAP Proposal.xlsm","20/05/2016 10:41:08"
What i would like to do is copy the above..
"X:\clients\A90\201AA3.05\2012.08 RAP Proposal.xlsm" to a new location with differnet drive, but same directory structure. So in the csv file i have the filename and path, but am unsure how to split the drive from there and make a variable.
I have a foreach loop..
$ToCopy = Import-Csv "c:\temp\log.csv"
foreach($Line in $ToCopy)
{
$FullPath = $Line.ParentFolder
$File = $Line.Name
$FullName = $Line.FullName
$file = "$FullPath\$FullName"
$DestPath = Split-Path $FullPath -NoQualifier
Copy-Item "$FullName" -Destination c:\test\$DestPath
}
Error message that i am getting is :
+ CategoryInfo : NotSpecified: (:) [Copy-Item], DirectoryNotFoundException
+ FullyQualifiedErrorId : System.IO.DirectoryNotFoundException,Microsoft.PowerShell.Commands.CopyItemCommand
Copy-Item : Could not find a part of the path 'C:\test\clients\A90\Support\_index0901\'.
At line:9 char:9
+ Copy-Item "$FullName" -Destination c:\test\$DestPath
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : NotSpecified: (:) [Copy-Item], DirectoryNotFoundException
+ FullyQualifiedErrorId : System.IO.DirectoryNotFoundException,Microsoft.PowerShell.Commands.CopyItemCommand
You get the error because the directory structure of your target path probably does not exist
To solve that you can create a 'temporary' file with New-Item ... -Force which creates the missing directories if necessary and then overwrite that file with Copy-Item like so
$ToCopy = Import-Csv "c:\temp\log.csv"
foreach($Line in $ToCopy)
{
$FullPath = $Line.ParentFolder
$File = $Line.Name
$FullName = $Line.FullName
$file = "$FullPath\$FullName"
$DestPath = Split-Path $FullPath -NoQualifier
$DestFile = c:\test\$DestPath
New-Item -ItemType File -Force $DestFile
Copy-Item "$FullName" -Destination $DestFile -Force
}
You need to create the folders before attempting to copy files in them.
Here's a way to do it, simplified from what you have, but with an added line to take care of the folders' creation.
foreach($File in $ToCopy)
{
$DestPath = Join-Path -Path 'c:\test' -ChildPath ( Split-Path $File.ParentFolder -NoQualifier )
If ( -not ( Test-Path -Path $DestPath ) ) { New-Item -Path $DestPath -Force -ItemType Directory }
Copy-Item $File.FullName -Destination $DestPath -WhatIf
}
(Be careful, I change the iteration variable from $Line to $File)
You are trying to copy files into c:\test\ directory which does not exist. Create this directory before loop:
mkdir c:\test\
or, in case directory may exist
mkdir c:\test\ -Force