Quite new to Powershell and scripting/programming and have a pretty basic problem I'm stuck with.
If I have a structure such as this:
Set-Location $PSScriptRoot
And do the following, I get the folders within the Logfiles folder:
$folders = Get-ChildItem -Directory -Path .\Logfiles -Recurse
If I then do the following I can see the first subfolder in "Logfiles"
$folders[0]
But now if I do the following, it seems to be using the "Scripts" folder instead of "Logfiles" as a root folder:
Get-ChildItem $folders[0]
or
Get-ChildItem .\Logfiles\$folders[0]
...(gives a null result)
Does anyone have any information on how directories work within powershell commands? I'm guessing I'm making a very basic mistake with handling the commands!!
Try
Get-ChildItem ".\Logfiles\$($folders[0].Name)"
Or
Get-ChildItem $folders[0].FullName
Or my favourite
$folders[0] | Get-ChildItem
PowerShell takes $folders[0] - which resolves to a [DirectoryInfo] object - and attempts to convert it to a string that it can bind to Get-ChildItem's -Path parameter.
But converting the directory object to a string results in just its name, the information about its location gets lost in the process.
Instead, you'll want to either do:
$folders[0] |Get-ChildItem
... which will cause PowerShell to correctly bind the full path of the directory object - or you can pass the full path as the argument to -Path:
Get-ChildItem $folders[0].FullName
Related
I am trying to use powershell to update some programs for my company. I am writing a script to do so (as instructed). When I install the new version of the program on the machines, it also requires me to 'upgrade' existing folders to match the new version of the software.
I need to find all of the folders that contain a certain hidden folder(let the name of said folder be .blah). I am trying to use the get-childitem command, with -path [drives to check] -Recurse -Directory -Force -EA SilentlyContinue. However, I am not sure how to filter correctly to only find folders that contain the .blah folder inside of it.
Help would be very much appreciated.
Combine your Get-ChildItem call with a Where-Object call that tests for a child directory of a given name using Test-Path:
# Note: "." refers to the *current* directory
# Adjust as needed.
Get-ChildItem -LiteralPath . -Recurse -Directory -Force -ErrorAction Ignore |
Where-Object {
Test-Path -ItemType Container -LiteralPath "$($_.FullName)\.blah"
}
The Get-ChildItem call outputs all directories (-Directory) in the entire directory subtree (-Recurse), including hidden ones (-Force), ignoring any errors (such as from lack of permissions, -ErrorAction Ignore).
The Where-Object call calls Test-Path to look for a .blah child directory (-ItemType Container) in the directory at hand ($_).
With a -LiteralPath argument, Test-Path finds the specified path if it exists, irrespective of whether the target file or directory is hidden.
By contrast, with a wildcard-based -Path argument, hidden items are not found, and given that, as of PowerShell 7.2.5, Test-Path has no -Force switch, there is no way to force their inclusion; this gap in functionality is the subject of GitHub issue #6501.
Note: In PowerShell (Core) 7+, you could simplify "$($_.FullName)\.blah" to "$_\.blah", because the [System.IO.DirectoryInfo] and [System.IO.FileInfo] instances output by Get-ChildItem and Get-Item there consistently stringify to their full path (.FullName) property, unlike in WindowsPowerShell, where they situationally stringify by their file/directory name only - see this answer.
All,
My intention is to copy all the files with starting with the name 'US.Services' and with the extension .dll from a directory and its sub directories to the place where the script is being executed, i have the following but nothing gets copied. Any help would be appreciated.
Get-Childitem -Path ".\.\" -Filter *US.Services*.dll -Recurse |
Copy-Item -Destination "."
Thanks -Nen
Since PowerShell v3 can use the $PSScriptRoot automatic variable to refer to the location where the script is saved (in PowerShell v2 that would be $here = $MyInvocation.MyCommand.Path | Split-Path.
Be aware the both those approaches work only when the script is executed, if you just paste them to PowerShell console they won't return any value.
If I understand your question correctly you look for files that start with the given string and end with the extension, so you need to use the * wildcard here: US.Services*.dll.
Get-Childitem -Path $PSScriptRoot -Recurse -Filter "US.Services*.dll" |
Copy-Item -Destination $PSScriptRoot
This will likely produce exceptions if there are files with the same name copied to the single directory, as two files cannot be named the same within single directory.
Given that Get-ChildItem -Path *.exe will show all the executables in the current directory, why doesn't Get-ChildItem -File -Include *.exe return the same result? Both commands are executed in the same directory, first command (with -Path) returns a list of executables but the second command (with -File) doesn't. (gci -File will list everything including the exe)
Get-ChildItem -File | gm #=> FileInfo
Get-ChildItem *.* | gm #=> DirectoryInfo and FileInfo
All the commands bellow return objects of type FileInfo
Get-ChildItem -File
Get-ChildItem *.* -Include *.exe
Get-ChildItem -Path *.exe
But mixing -File and -Include/-Exclude returns nothing, even though the -include is looking for a filetype:
Get-ChildItem -File -Include *.exe #=> Returns nothing
What am I missing here?
From TechNet:
The Include parameter is effective only when the command includes the
Recurse parameter or the path leads to the contents of a directory,
such as C:\Windows*, where the wildcard character specifies the
contents of the C:\Windows directory.
In other words, when you use the Include parameter, it does not automatically consider all files and directories unless you use the Path or the Recurse parameters. Notice, that when just using the Path parameter, you must include a wildcard to force it to consider the file and directory results underneath that path. I cannot think of why this is.
To get your examples to work, you would use one of the following (I'm dropping the File parameter because it seems redundant):
Get-ChildItem -Path * -Include *.exe
Get-ChildItem -Include *.exe -Recurse
The gist of my answer to your question is an opinion tho - from what I've seen the Include parameter should be removed - or its behavior repaired to match the default behavior of the Get-ChildItem cmdlet when used without parameters. There may be a good explanation to why it works this way, but I'm unaware of this.
If you drop the Include parameter from your examples, the behavior/results make more sense (to me):
Get-ChildItem -Path *.exe
In this case, we would only need the Exclude parameter to effectively cover all filtering requirements. Something like:
Get-ChildItem -Path *.exe -Exclude *system*
The below script doesn't error out and it doesn't work. I have trapped it inside of a try catch block and that isn't working either. I am attempting to move only pdb, and dll files to a certain folder. However, when I run this script, the dll's and pdb's aren't moved. I probably have an order of operations mixup or something, but I thought this script should have worked...
gci -path $FromPath -Include ("*.dll", "*.pdp") | ? {$_.Name -match "PackageServiceLib|Package.capture.CSE.inc|PackageDBCore|Package.capture|PackageCommon|PackageServiceFramework"} | Copy-item -path $FromPath -destination $ToPath -force
My guess is that your $FromPath variable doesn't specify \* at the end. If you don't specify that, then your -Include parameter will be useless.
Assuming that a folder named c:\test contains 10 files with a .txt file extension, consider the difference between this:
Get-ChildItem -Path c:\test -Include *.txt;
And this:
Get-ChildItem -Path c:\test\* -Include *.txt;
The first command will yield no output, because you are getting the directory, not the children of the directory. In the second command, we are specifying that we want everything that is a child of the directory, except we only want the items that match the -Include parameter.
I need to copy all my fileserver psts to another location with their folder paths.
I did the following
Get-ChildItem D: -recurse -include *.pst | copy-item -destination z:\
But this resulted in copies of like filenames being created.
I need the copy to write out the path name (its home folders so the pathname will help with easy ownership)
Any suggestions?
You could use the -recurse and -force flag on copy-item. It might create the folder structure. If it doesn't, you can use New-item to create that structure with a bit of work. If you're looking for an answer like that (i.e. you want folder structure copied as well) update your question with more detail and you'll get an answer focused on that.
What I would do, if I was just looking for a unique name for each PST, is to convert the full name to a file name on Z:, like so:
$psts = Get-ChildItem D:\ -recurse -include "*.pst"
$psts | % {
Copy-Item $_.FullName -Destination ($_.FullName.Replace("D:\","Z:\").Replace("\","-"))
}
It might be messy, but it should be unique.