Combining results from two calls to Select-Object - powershell

As part of a PowerShell script, I want to generate a list of subfolders of two different folders. I approached this by calling Get-ChildItem twice, using Select-Object to transform the paths, and trying to combine the results. However, this is the combining step where I got stuck. I have tried this:
$cur = Get-Location
$mainDirs = Get-ChildItem -Directory -Name | Select-Object {"$cur\$_"}
$appDirs = Get-ChildItem -Directory -Name Applications\Programs |
Select-Object {"$cur\Applications\Programs\$_"}
$dirs = $mainDirs,$appDirs #Doesn't work!
But $dirs ends up consisting of the entries from $mainDirs followed by as many null items as many items there are in $appDirs.
How can I combine these in PowerShell?
Edit: The output of mainDirs[0]:
"$cur\$_"
---------
D:\somefolder\somesubfolder
The output of appDirs[0]:
"$cur\Applications\Programs\$_"
-------------------------------
D:\somefolder\Applications\Programs\othersubfolder

Get-ChildItem accepts a string array as input. Simply pass both folders whose subfolders you want listed as an array. Expand the FullName property to get the paths of subfolders:
$folders = '.', '.\Applications\Programs'
$dirs = Get-ChildItem $folders -Directory | Select-Object -Expand FullName
If you want the relative rather than the absolute path remove the current directory from the beginning of the path strings:
$pattern = '^{0}\\' -f [regex]::Escape($PWD.Path)
$folders = '.', '.\Applications\Programs'
$dirs = Get-ChildItem $folders -Directory |
ForEach-Object { $_.FullName -replace $pattern }

Related

remove duplicates while combining System.IO.FileInfo objects

I'm trying to combine System.IO.FileInfo objects (from distinct Get-ChildItem calls) together. I've found working solutions (i.e. using PowerShell array) from this question:
Combine the results of two distinct Get-ChildItem calls into single variable to do the same processing on them
$target = "C:\example"
$Files = #( Get-ChildItem -LiteralPath $target -Force -Attributes !D )
$Files += #( Get-ChildItem -LiteralPath $target -Force -Attributes !D ) # for demo. & simplicity, I'm using the same path here
$Files | Write-Host # here the same entries are duplicated
However, the same entries from the System.IO.FileInfo objects are duplicated in the resulting object. I'm wondering if there is an elegant way to combine the objects while removing the duplicates?
PS: Files are "duplicated" if they have the same ".FullName".
$Files = #($Files | Sort-Object -Property FullName -Unique)

Add list of files in a directory to array list

I am trying to save the list of files in a directory to array list, can you please share the code snippet for Windows PowerShell.
I have 2 files under c:\temp
file1: stack.zip
file2: overflow.zip
Need to store file1 & file2 in a array called
$arrlst = ['stack.zip','overflow.zip']
Set-Location -Path "c:\temp"
fileslst = Get-children
$arrlst = [filelist]
Running the below will get you what you are after.
[System.Collections.ArrayList]$arrlst = #(
$(Get-ChildItem -File -Path 'C:\temp' | Select -ExpandProperty Name)
)
You need to do Select -ExpandProperty Name to ensure that the only result from the Get-ChildItem is the filename including extension (Name).
$scriptpath='c:\temp'
$fileNames = Get-ChildItem -File -Path $scriptPath -Recurse -Include *.zip | Select -ExpandProperty Name
foreach ($vinodh in $fileNames)
{
write-host $vinodh
}

Search a specified path for multiple .xml files within the same folder

I am seeking help creating a PowerShell script which will search a specified path for multiple .xml files within the same folder.
The script should provide the full path of the file(s) if found.
The script should also provide a date.
Here's my code:
$Dir = Get-ChildItem C:\windows\system32 -Recurse
#$Dir | Get-Member
$List = $Dir | where {$_.Extension -eq ".xml"}
$List | Format-Table Name
$folder = "C:\Windows\System32"
$results = Get-ChildItem -Path $folder -File -Include "*.xml" | Select Name, FullName, LastWriteTime
This will return all xml files only and display the file name, full path to the file and last time it was written to. The "-File" switch is only available in Powershell 4 and up. So if doing it off a Windows 7 or Windows 2008 R2 Server, you will have to make sure you updated your WMF to 4 or higher. Without file the second like will look like.
#Powershell 2.0
$results = Get-ChildItem -Path $folder -Include "*.xml" | Where {$_.PSIsContainer -eq $false} | Select Name, FullName, LastWriteTime
I like the Select method mentioned above for the simpler syntax, but if for some reason you just want the file names with their absolute path and without the column header that comes with piping to Select (perhaps because it will be used as input to another script, or piped to another function) you could do the following:
$folder = 'C:\path\to\folder'
Get-ChildItem -Path $folder -Filter *.xml -File -Name | ForEach-Object {
[System.IO.Path]::GetFullPath($_)
}
I'm not sure if Select lets you leave out the header.
You could also take a look at this answer to give you some more ideas or things to try if you need the results sorted, or the file extension removed:
https://stackoverflow.com/a/31049571/10193624
I was able to make a few changes exporting the results to a .txt file, but though it provides the results I only want to isolate the same .xml files.
$ParentFolder = "C:\software"
$FolderHash = #{}
$Subfolders = Get-ChildItem -Path $ParentFolder
foreach ($EventFolder in $Subfolders) {
$XMLFiles = Get-ChildItem -Path $EventFolder.fullname -Filter *.xml*
if ($XMLFiles.Count -gt 1) {
$FolderHash += #{$EventFolder.FullName = $EventFolder.LastWriteTime}
}
}
$FolderHash
Judging from your self-answer you want a list of directories that contain more than one XML file without recursively searching those directories. In that case your code could be simplified to something like this:
Get-ChildItem "${ParentFolder}\*\*.xml" |
Group-Object Directory |
Where-Object { $_.Count -ge 2 } |
Select-Object Name, #{n='LastWriteTime';e={(Get-Item $_.Name).LastWriteTime}}

Recursively Delete Files and Directories Using a Filter on the Directory Name

I am attempting to delete all directories, sub-directories, and the files contained in them based on a filter that specifies the required directory/sub-directory name.
For example, if I have c:\Test\A\B.doc, c:\Test\B\A\C.doc, and c:\Test\B\A.doc and my filter specifies all directories named 'A', I would expect the remaining folders and files to be c:\Test, c:\Test\B and c:\Test\B\A.doc respectively.
I am trying to do this in PowerShell and am not familiar with it.
The following 2 examples will delete all of the files that match my specified filter, but the files that match the filter as well.
$source = "C:\Powershell_Test" #location of directory to search
$strings = #("A")
cd ($source);
Get-ChildItem -Include ($strings) -Recurse -Force | Remove-Item -Force –Recurse
and
Remove-Item -Path C:\Powershell_Test -Filter A
I would use something like this:
$source = 'C:\root\folder'
$names = #('A')
Get-ChildItem $source -Recurse -Force |
Where-Object { $_.PSIsContainer -and $names -contains $_.Name } |
Sort-Object FullName -Descending |
Remove-Item -Recurse -Force
The Where-Object clause restricts the output from Get-ChildItem to just folders whose names are present in the array $names. Sorting the remaining items by their full name in descending order ensures that child folders get deleted before their parent. That way you avoid errors from attempting to delete a folder that had already been deleted by a prior recursive delete operation.
If you have PowerShell v3 or newer you can do all filtering directly with Get-ChildItem:
Get-ChildItem $source -Directory -Include $names -Recurse -Force |
Sort-Object FullName -Descending |
Remove-Item -Recurse -Force
I don't think you can do it quite that simply. This gets the list of directories, and breaks the path into its constituent parts, and verifies whether the filter matches one of those parts. If so, it removes the whole path.
It adds a little caution to handle if it already deleted a directory because of nesting (the test-path) and the -Confirm helps ensure that if there's a bug here you have a chance to verify the behavior.
$source = "C:\Powershell_Test" #location of directory to search
$filter = "A"
Get-Childitem -Directory -Recurse $source |
Where-Object { $_.FullName.Split([IO.Path]::DirectorySeparatorChar).Contains($filter) } |
ForEach-Object { $_.FullName; if (Test-Path $_) { Remove-Item $_ -Recurse -Force -Confirm } }

Delete files defined in an array with Powershell

Is it possible to define an array of filenames (all files in different folders) and then in a loop delete them all, or do something else?
Actually I need to create a few symbolic links using mklink to one file, putting those links in a different folders, replacing the old links if there was any.
Deleting an array of filenames is simple:
Remove-Item foo.txt,c:\temp\bar.txt,baz\baz.txt
Or via a variable:
$files = 'foo.txt','c:\temp\bar.txt','baz\baz.txt'
Remove-Item $files
And then based on all files in different folders:
$folders = 'C:\temp','C:\users\joe\foo'
Get-ChildItem $folders -r | Where {!$_.PSIsContainer} | Remove-Item -WhatIf
Remove the -WhatIf to do the actual removal.
If you want to delete a file with a specific name you could use the -Filter parameter on Get-ChildItem. This would be the best performing approach:
$folders = 'C:\temp','C:\users\joe\foo'
Get-ChildItem $folders -r -filter foo.bak | Remove-Item -WhatIf
If the name requires more sophisticated matching then you can use a regex in a Where scriptblock e.g.:
$folders = 'C:\temp','C:\users\joe\foo'
Get-ChildItem $folders -r | Where {$_.Name -match 'f\d+.bak$'} |
Remove-Item -WhatIf
something like this should work:
can't test right now, sorry
$filenames = #('filename1.txt', 'filename2.txt', 'filename3.txt')
foreach($file in $filenames)
{
#GCI recursive to find all instances of this filename
$filesToDelete = Get-ChildItem -R | where {$_.Name -eq $file}
foreach($f in $filesToDelete)
{
#delete the file that matches, etc. here
# just using Write-Host to echo out the name for now
Write-Host $f.Name
}
}
As with most powershell, you can really compress this, but wanted to extend for explanation.
You could extend this to match your needs. For example if you needed all files that contain the word "delete", you could do gci | where {$_.Name -like "$file"}