Storing directory names in list and displaying - arrays

I am trying to do a mass import of tables into SQL. To do this I need to open a main directory and then cycle through those sub-directories to execute the actual files. I cannot seem to store these sub-directory names in a list.
Here is my code:
$path = "E:\Dictionary_SQL_Commands\";
$i = 0;
#I would like to dynamically allocate this space as I do not know the length
$global:contents = new-object object[] 10;
foreach ($item in $path){
$global:contents[$i] = $local:item.name;
$i++;
}
$contents gets created and I can view it using gci variable: but the output is {$null,$null,...}.

You don't need a "list". This is Powershell.
# Get all File items in the given path recursively #
Get-ChildItem -Path:$path -Recurse -File |
# Process each one as it's available #
Foreach-Object {
# Get the contents of each file #
$Contents = Get-Content $_;
# do other stuff with $Contents here #
}
This is the Powershell pipeline

Related

Cannot remove a string from an array in powershell

I'm trying to populate an array of file paths where ever the script is located in. But I don't want
the array to include the path of the script only the other files in that folder. I have tried removing it after it is populated by using a list array instead but then I get an error that the array is a fixed size.
#To get path in which the script is located
$mypath = $MyInvocation.MyCommand.Path
$myStringPath=$mypath.ToString().Replace("TestingScriptPath.ps1", "")
#Populates files inside the folder
$array = #()
(Get-ChildItem -Path $myStringPath ).FullName |
foreach{
$array += $_
}
#display paths
for($i = 0; $i -lt $array.length; $i++)
{
$array[$i]
}
You're better off not putting it in the array in the first place.
When updating an array the whole array has to be rewritten, so the performance tends to be terrible.
Use a different datatype if you're going to be removing item-by-item.
#To get path in which the script is located
$mypath = $MyInvocation.MyCommand.Path
$myStringPath=$mypath.ToString().Replace("testingscriptpath.ps1", "")
#Populates files inside the folder
$array = Get-ChildItem -Path $myStringPath | Where-Object {$_.fullname -ne $mypath}
$array
if you definitely want to do it the way suggested in the question (slower)
$ArrayWithFile = Get-ChildItem -Path $myStringPath
$ArrayWithoutFile = $ArrayWithFile | Where-Object {$_.fullName -ne $mypath}

Powershell read filenames under folder and read each file content to create menu items

I've a folder called c:\mycommands
files under this folder are multiple files like:
command1.txt
command2.txt
command3.txt
each file has one line only, like this:
in file command1.txt:
echo "this is command1"
in file command2.txt"
echo "this is command2"
and so on
I want to read the filename and it's content into an array/variable pair in order to build a dynamic menu.
so theoretically, all I would need to do in the future is to, drop a file into the folder and program will include it as menu option dynamically. (or remove the file to have it not show up in menu option.
What's the best way to approach this? maybe a do while loop with get-content into an array? Any input would be greatly appreciated. I'm really trying limit or avoid menu maintenance but would rather have the menu bre created dynamically
Here are three variations on the same basic idea, depending on what kind of output you need.
# Storing output in a hash table (key/value pairs)
$resultHash = #{}
Get-ChildItem -Path C:\mycommands -File |
ForEach-Object {$resultHash.Add($_.Name, (Get-Content -Path $_.FullName))}
# Storing output in an array of psobjects
$resultArray = #()
Get-ChildItem -Path C:\mycommands -File |
ForEach-Object {
$resultArray += (New-Object -TypeName psobject -Property #{"NameOfFile"=$_.Name; "CommandText"=(Get-Content -Path $_.FullName);})
}
# Outputting psobjects to the pipeline
Get-ChildItem -Path C:\mycommands -File |
ForEach-Object {
New-Object -TypeName psobject -Property #{"NameOfFile"=$_.Name; "CommandText"=(Get-Content -Path $_.FullName);}
}
# Making a nice menu out of the hash table version
$promptTitle = "My menu"
$promptMessage = "Choose from the options below"
$promptOptions = #()
foreach ($key in $resultHash.Keys)
{
$promptOptions += New-Object System.Management.Automation.Host.ChoiceDescription $key, $resultHash[$key]
}
$promptResponse = $host.ui.PromptForChoice($promptTitle, $promptMessage, $promptOptions, 0)
If I am understanding what you want correctly, this might be able to accomplish it for you.
If will gather a list of all the files in a folder, then get the content from each one and add them to an Array one by one.
[System.Collections.ArrayList]$Files = #(Get-ChildItem "C:\Logs\" |
Where-Object {$_.PSIsContainer -eq $false} |
Select-Object FullName)
[System.Collections.ArrayList]$List_Of_Commands = #()
foreach ($File in $Files) {
[System.Collections.ArrayList]$File_Contents = #(Get-Content $File.FullName)
foreach ($Content in $File_Contents) {
$Array_Object = [PSCustomObject]#{
'Command' = $Content
}
$List_Of_Commands.Add($Array_Object) | Out-Null
}
}
$List_Of_Commands

Find size of folders in an array using PowerShell

I have an array of folders, called $FolderArray. It contains about 40 folders. Inside each folder are a bunch of txt files. I want to loop through each folder to get the number of files in each folder, as well as the total size of each folder. I got the number of files in each folder to work, but for the folder size, it ends up outputting the file size of the last file in each folder.
I pulled this out of a larger snippet of my code, so if anything needs more clarification please let me know. I appreciate the help!
$ProcessedLocation = "C:\Users\User.Name\Documents"
$FolderArray = gci -Path $ProcessedLocation | Where-Object {$_.PSIsContainer} | Foreach-Object {$_.Name}
Foreach ($i in $FolderArray)
{
$FolderLocation = $ProcessedLocation + $i
[int]$FilesInFolder = 0
Get-ChildItem -Path $FolderLocation -Recurse -Include '*.txt' | % {
$FilesInFolder = $FilesInFolder + 1
$Length = $_.Length
$FolderSize = $FolderSize + $Length
}
Write-Host $FolderSize
}
You are iterating over $FolderArray twice, once in the foreach($i in $FolderArray) loop, and then again inside the loop body:
foreach($i in $FolderArray){
Get-ChildItem $FolderArray # don't do this
}
If you want to look into each folder in $FolderArray individually, reference the current variable (in your example that would be $i).
I would recommend saving the output from Get-ChildItem to a variable and then grab the size and count of the files from that:
# keep folders as DirectoryInfo objects rather than strings
$FolderArray = Get-ChildItem -Path $ProcessedLocation
foreach ($Folder in $FolderArray)
{
# retrieve all *.txt files in $Folder
$TxtFiles = Get-ChildItem -Path $Folder -Recurse -Include '*.txt'
# get the file count
$FilesInFolder = $TxtFiles.Count
# calculate folder size
$FolderSize = ($TxtFiles | Measure -Sum Length).Sum
# write folder size to host
$FolderSizeMB = $FolderSize / 1MB
Write-Host "$Folder is $FolderSizeMB MB in size"
}

Comparing files within folders and moving files not found in one folder to a different location

I am working on folders that contain many types and sizes of files within them. What I want to do is move files that are not contained in one folder into a new folder. I have embedded a picture link that helps illustrate what I am aiming to do.
I would like test123.pdf to be moved to a new location because it's not contained within the other folder. Below I have some code that simply compares the contents of each folder and outputs which file is out of place. I have been researching some things online, but have come up empty. Can anyone help me proceed?
Disclaimer: I know the path is wrong, but I can't show it for security reasons.
$Folder1 = Get-ChildItem -Recurse -path "Enter Path here"
$Folder2 = Get-ChildItem -Recurse -path "Enter the Path here"
Compare-Object -ReferenceObject $Folder1 -DifferenceObject $Folder2
It sounds like you want to compare the contents of two folders, ID the file(s) that are not present in both folders, and then move them to a third folder. To accomplish this, you can define your 2 paths in variables, compare the contents of the folders, grab the full path names of the different items, and then move them to the new destination.
$path1 = yourfirstpath
$path2 = yoursecondpathforcomparing
$path3 = yourdestinationpath
diff (ls $path1 -recurse) (ls $path2 -recurse) | ForEach {$_.InputObject.FullName} | Move-Item -Destination $path3
diff = Compare-Object , ls = Get-ChildItem
This will do the work, any file that is not in both Folder1 & Folder2 will be moved to Folder 3
$Folder1 = 'C:\folder1'
$Folder2 = 'C:\folder2'
$Folder3 = 'C:\folder3'
foreach ($file in Get-ChildItem -Recurse $Folder1)
{
if (-not(Test-Path "$Folder2\$file"))
{
Move-Item $file.FullName $Folder3
}
}
This will compare by file name, and maintain the directory structure the extra files were found in, and handle the recursion properly. The output of the code demonstrates the directory structure I tested with.
# be explict here to ensure everything is lowercase
# so when this is cut and pasted, it does not break
# when you enter the real path
$d1 = "d:\test\one".ToLower()
$d2 = "d:\test\two".ToLower()
$f1 = gci -Recurse $d1 -File | % {$_.FullName.ToLower()}
$f2 = gci -Recurse $d2 -File | % {$_.FullName.ToLower()}
"f1"
$f1
"`nf2"
$f2
$same = #()
$extra = #()
foreach ($f in $f2)
{
$f2tof1path = $f.Replace($d2, $d1)
if ($f1.Contains($f2tof1path) -eq $false)
{
$extra += $f
}
else {
$same += $f
}
}
"`nSame"
$same
"`nExtra"
$extra
"`nMOVE"
$folder3 = "d:\test\three"
foreach ($f in $extra)
{
# move files somewhere, create dir if not exists
$dest = $f.Replace($d2,$folder3)
$destdir = $(Split-Path -Parent -Path $dest)
if (!(Test-Path $destdir))
{
# remove quotes to do new-item, keep them to show what it will do
"New-Item -ItemType Directory -Force -Path $destdir"
}
# remove quotes to do move-item, keep them to show what it will do
"Move-Item $f $dest"
}
Output
f1
d:\test\one\1.txt
d:\test\one\2.txt
d:\test\one\sub\1.txt
d:\test\one\sub\2.txt
f2
d:\test\two\1.txt
d:\test\two\2.txt
d:\test\two\3.txt
d:\test\two\sub\1.txt
d:\test\two\sub\2.txt
d:\test\two\sub\3.txt
Same
d:\test\two\1.txt
d:\test\two\2.txt
d:\test\two\sub\1.txt
d:\test\two\sub\2.txt
Extra
d:\test\two\3.txt
d:\test\two\sub\3.txt
MOVE
New-Item -ItemType Directory -Force -Path d:\test\three
Move-Item d:\test\two\3.txt d:\test\three\3.txt
New-Item -ItemType Directory -Force -Path d:\test\three\sub
Move-Item d:\test\two\sub\3.txt d:\test\three\sub\3.txt
If this does not solve your problem, it should get you 99% there. Play around with the code, have fun, and good luck.

Storing Directory Folder Names Into Array Powershell

I am trying to write a script that will get the names of all the folders in a specific directory and then return each as an entry in an array. From here I was going to use each array element to run a larger loop that uses each element as a parameter for a later function call. All of this is through powershell.
At the moment I have this code:
function Get-Directorys
{
$path = gci \\QNAP\wpbackup\
foreach ($item.name in $path)
{
$a = $item.name
}
}
The $path line is correct and gets me all of the directories, however the foreach loop is the problem where it actually stores the individual chars of the first directory instead of each directories full name to each element.
Here's another option using a pipeline:
$arr = Get-ChildItem \\QNAP\wpbackup |
Where-Object {$_.PSIsContainer} |
Foreach-Object {$_.Name}
$array = (dir *.txt).FullName
$array is now a list of paths for all text files in the directory.
For completeness, and readability:
This get all files in "somefolder" starting with 'F' to an array.
$FileNames = Get-ChildItem -Path '.\somefolder\' -Name 'F*' -File
This gets all directories of current directory:
$FileNames = Get-ChildItem -Path '.\' -Directory
# initialize the items variable with the
# contents of a directory
$items = Get-ChildItem -Path "c:\temp"
# enumerate the items array
foreach ($item in $items)
{
# if the item is a directory, then process it.
if ($item.Attributes -eq "Directory")
{
Write-Host $item.Name//displaying
$array=$item.Name//storing in array
}
}
I believe the problem is that your foreach loop variable is $item.name. What you want is a loop variable named $item, and you will access the name property on each one.
I.e.,
foreach ($item in $path)
{
$item.name
}
Also take note that I've left $item.name unassigned. In Powershell, if the result isn't stored in a variable, piped to another command, or otherwise captured, it is included in the function's return value.

Resources