I am working on a script to automate adding users. I want to read from all CSV files in a directory until they are done and then I want to move those csvs to an archive. In the program I am checking a txt file to make sure another instance of the program is not already running. after that I am allowing the code to run or the program to end. When I run the program with 1 or two test files named test.csv and test2.csv I am not having any errors. Once I add random names .csv and try to run these through I am getting the error that import-csv cannot find the file and the path is is telling me the file at it no correct, its from the location of the script.
Here is my code:
$fileDirectory = "c:\test";
$CheckRun = Get-Content c:\test\checkrun.txt
Write-Host $($CheckRun)
if($CheckRun -eq "notrunning") {
Get-ChildItem $fileDirectory -Filter *.csv | Foreach-Object {
$list= Import-Csv $_
$State = "running"
$basename = $_.BaseName
$file = $FileDirectory + "\" + $basename + ".csv"
$ArchiveFile = $fileDirectory + "\archive\" + $basename + "old.csv"
foreach ($entry in $list) {
# will run command here using the entries from the CSVs
write-Host $($entry.EMAIL) $($entry.FIRSTNAME) $($entry.LASTNAME) $($entry.PASSWORD)
}
Move-Item $($file) ${ArchiveFile} -force
Write-Host "Press any key to continue ..."
$x = $host.UI.RawUI.ReadKey("NoEcho,IncludeKeyDown")
$State > c:\test\Checkrun.txt
}
$State = "notrunning"
$State > c:\test\Checkrun.txt
Write-Host "Press any key to continue ..."
$x = $host.UI.RawUI.ReadKey("NoEcho,IncludeKeyDown")
}
else {
Write-Host "Press any key to continue ..."
$x = $host.UI.RawUI.ReadKey("NoEcho,IncludeKeyDown")
exit
}
When you get the child items you are getting a file object. Try referenceing the fullname instead it workd for me:
Get-ChildItem $fileDirectory -Filter *.csv | Foreach-Object {
$list= Import-Csv $_.fullname
Otherwise it is trying to look in the path that you are running the script for the file instead of C:\test\filename.csv
Related
The action I am supposed to do:
Read a file from a folder
Extract a date from the 1st line
Change it to 'yyyymmdd' format
Rename all the file by removing first 4 characters and place this format date at the beginning.
Example FILE.FILE will be changed to 20180725.FILE (The date will be in the file)
I am able to accomplish this to a single folder in Newpath by the following code:
$path="\\Data\DEV\DevDat\Arun\DXSL\Newpath\20170601"
$files=Get-ChildItem $path | Select-Object -first 1
$data = Get-Content "$path\$files" -first 1
foreach($line in $data)
{
$arr = $line.substring(52,4)+$line.substring(46,2)+$line.substring(49,2)
}
get-childitem $path | rename-item -newname { $arr +[string]($_.name).substring(4)}
However, I am not able to replicate this action to the other folders in a loop. The Newpath folder has several sub-folders. I need to rename the files inside each sub-folder inside Newpath. Is there any way to achieve this?
FYI I'm using Version 4 of powershell.
A PowerShell script as suggested in my comment.
It does not check if the file to rename to already exists.
The Rename-Item has the parameer -WhatIf appended, so it only shows what would be done.
If there are more numbers in the first line, the script will match the first pattern.
The script also does not check if the file already is renamed to the pattern.
## Q:\Test\2018\07\25\SO_51522205.ps1
#Requires -Version 3.0
$BasePath = "\\Data\DEV\DevDat\Arun\DXSL\Newpath"
$RE = [RegEx]'(?<Month>\d{2}).(?<Day>\d{2}).(?<Year>\d{4})'
ForEach ($Folder in (Get-ChildItem -Path "$BasePath\*" -Directory)){
ForEach ($File in (Get-ChildItem -Path "$($Folder.FullName)\*" -File)){
$Line1 = (Get-Content $File.FullName | Select-Object -First 1)
If ($File.BaseName.Length -gt 4){
$BaseName = $File.BaseName.SubString(4)
} else {
$BaseName = ''
}
If ($Line1 -match $RE){
$NewName = ("{0}{1}{2}{3}{4}" -f `
$Matches.Year,
$Matches.Month,
$Matches.Day,
$BaseName,
$File.Extension)
$File | Rename-Item -NewName $NewName -WhatIf
} Else {
"{0} doesn't have a proper date in 1st line" -f $File.FullName
}
}
}
Sample tree before,
> tree /F
└───Newpath
└───20170601
blahblah.txt
FILE.FILE
after running the script.
> tree /F
└───Newpath
└───20170601
20180724blah.txt
20180725.FILE
I have a script that needs to copy a list of files to ceraitn directories and locations on target servers.
I was able to understand that I need to creat an csv file as follows:
I need to understand from you how to make the files from source location to their adjacent file in target location. Any ideas?
My code looks like this:
# customize log file
$date = (Get-Date -Format d).ToString() | foreach {$_ -replace "/", "_"}
$time = (Get-Date)
$scriptDir = "D:\Scripts\ServerBuildToolkitT1\SingleFileUpfate\"
$logDir = "D:\Scripts\ServerBuildToolkitT1\Logs\SingleFileUpfate\"
$logFileName = "SingleFileUpfate $date.log"
$sources = #()
$destinsyions = #()
function CSV {
Import-Csv D:\Scripts_PS\SD.csv | ForEach-Object {
$sources += $_."Source Location"
$destinations += $_."Destination Location"
}
}
# this file contains the list of destination server that you want copy
# file/folder to
$computers = Get-Content "D:\Scripts_PS\ServerList.txt"
function main
{
foreach ($computer in $computers) {
foreach ($destination in $destinations) {
Write-Output "$([DateTime]::Now) Copying files update to $computer now" |
Out-File -FilePath "$logDir\$logFileName" -Append
Copy-Item $sources -Destination "\\$computer\$destination" -Force -Recurse -Verbose:$false
}
}
}
csv
main
Write-Output "$([DateTime]::Now) the operation SingleFileUpdate completed successefully" |
Out-File -FilePath "$logDir\$logFileName" -Append
i have updtaed the Script (as seen above) and now i am getting the following ERROR
"WARNING: One or more headers were not specified. Default names starting with "H" have been used in place of any missing headers."
I've a scenario where everyday I will received 2 csv files where the file naming is something like CMCS_{Timestamp}, example CMCS_02012016100101 and CMCS_02012016100102 . This 2 files are different files and have different structure, but because this 2 files will go into same folder where my ETL tools will pick it up and process. So I wrote a script where the script will based on the structure of the file to distinguish it whether is a file A or file B.
For File A, i tell a script to look at first line of the file and if line start with 'Name,Emp(Date).' then copy the file to folderA else if line start with 'Name,Group.' then copy the file to folderB else copy file to folder C
Here the code that i wrote, the powershell does not generate any errors but it does not produce any results too. I wonder what wrong in my script.
$fileDirectory = "D:\Data";
$output_path = "D:\Output\FileA";
$output_path2 = "D:\Output\FileB";
$output_path2 = "D:\Output\FileC";
foreach($file in Get-ChildItem $fileDirectory)
{
# the full file path.
$filePath = $fileDirectory + "\" + $file;
$getdata = Get-Content -path $filePath
$searchresults = $getdata | Select -Index 1 | Where-Object { $_ -like 'Name,Emp(Date).*' }
$searchresults2 = $getdata | Select -Index 1 | Where-Object { $_ -like 'Name,Group.*' }
if ($searchresults -ne $null) {
Copy-Item $filePath $output_path
}
if ($searchresults2 -ne $null) {
Copy-Item $filePath $output_path2
}
}
Your issue may be caused by the Select -Index 1, as Powershell uses 0 based indexing this will actually select the second line of the file. If you change this to 0 it should correctly get the header row.
On a separate note, instead of doing $filePath = $fileDirectory + "\" + $file; you can just use $file.FullName to get the file path.
EDIT:
I think this should do what you're after:
[string] $FileDirectory = "D:\Data";
[string] $OutputPath = "D:\Output\FileA";
[string] $OutputPath2 = "D:\Output\FileB";
[string] $OutputPath3 = "D:\Output\FileC";
foreach ($FilePath in Get-ChildItem $FileDirectory | Select-Object -ExpandProperty FullName)
{
[string] $Header = Get-Content $FilePath -First 1
if ($Header -match 'Name,Emp.*') {
Copy-Item $FilePath $OutputPath
}
elseif ($Header -match 'Name,Group.*') {
Copy-Item $FilePath $OutputPath2
}
else {
Copy-Item $FilePath $OutputPath3
}
}
I would like to identify a specific empty folder in our user profiles.
I have a text file containing all of our user names that I want the script to refer to. The script will loop each user directory and either output to file or screen and say if the directory is empty. Hidden files do not have to count!
Something similar
FOR /F %U IN (C:\UserList\UserList.TXT) DO *Find and List Empty Folder* \\Server\Share\%U\Target_Folder
Powershell solutions welcome!
This article on Technet provides the following Powershell code snippet to identify all empty folders:
$a = Get-ChildItem C:\Scripts -recurse | Where-Object {$_.PSIsContainer -eq $True}
$a | Where-Object {$_.GetFiles().Count -eq 0} | Select-Object FullName
Replace "C:\Scripts" with the root folder you want to search.
Update:
The following script will get you in the ballpark.
$content = Get-Content C:\Temp\FolderList.txt
foreach ($line in $content)
{
Write-Host $line -NoNewline
$testObject = Test-Path -Path $line
if ($testObject)
{
$folder = Get-Item -Path $line
$filesCount = $folder.GetFiles().Count
if ($filesCount.Equals(0))
{
Write-Host " - Empty folder"
}
else
{
Write-Host " - Contains files"
}
}
else
{
Write-Host " - Invalid path"
}
}
I have a simple PowerShell script that bulk renames files and I'd like to have a table output that shows 'Old File Name' and 'New File Name' to show the changes. How do I access/reference the new file name while still inside the 'ForEach-Object' loop, assuming it can be done? Can I refresh that particular value of $_? I don't want to just use my variable $newname because I created that and since this is supposed to be output that shows the file names were actually changed, I'd like to access the file's new name from the system as determined by the script.
Write-Host "Old Name `t`t`t`t`t`t New Name"
Write-Host "-------- `t`t`t`t`t`t --------"
$files = Get-ChildItem -Path C:\Users\<user>\Desktop\Config
$files | % ({
if ((!$_.PsIsContainer) -and ($_.Extension -eq '')) {
$oldname = $_.FullName
$newname = "$($_.FullName).cfg"
Rename-Item $oldname $newname
# $_.Name still refers to the old file name without the extension
# How do I immediately access its new name (including extension)?
Write-Host $_.Name `t`t`t`t`t`t $newname
}
})
You can do a Get-Item on $newname:
(Get-Item $newname).Name
I have taken the liberty to rewrite your Script a little, using a Hash Table and New-Object.
To explain what I'm doing here, I will split it a bit up for you.
First I declar some Variables, I'm gonna use in my foreach loop, with this:
Note: -File parameter, is so it will only take file names, if you like to rename everything, files and folder, then remove it.
$files = Get-ChildItem -Path "C:\Users\dha\Desktop\PS test folder" -File
$OldFiles = $files
[int]$i = "0"
Then I'm taking each file one by one, and creating the new name in:
$Newname = ("Blop" + "$i" + ".txt")
And then take the file info for one file, and pipe it to rename-item here
$File | Rename-Item -NewName $Newname
The $ixx is just a plusser so increase the file number by one for each time the foreach loop runs.
Then I'm writing a Hash Table with $Old_And_New variable.
Last, I'm creating a Object with New-object and outputting it.
I Hope this help's and my explanation is understandable.
To script assembled:
$files = Get-ChildItem -Path "C:\Users\dha\Desktop\PS test folder" -File
$OldFiles = $files
[int]$i = "0"
foreach ($File in $files)
{
$Newname = ("Blop" + "$i" + ".txt")
$File | Rename-Item -NewName $Newname
$i++
$Old_And_New = #{
'Old File Name' = "$OldFiles";
'New File Name' = "$Newname"
}
$obj = New-Object -TypeName PSObject -Property $Old_And_New
Write-Output $obj
}