Dealing with blank folder names while using get-childitem in powershell - powershell

I built a script, that searches through all directories recursively with Get-ChildItem. The problem is, there exist directories with blank names (done with alt+255).
When the script encounters such a directory, it still lists the files in this directory, but does not search in its sub-directories.

I don't think it is possible in powershell. but you can skip to cmd and use
cmd -c dir $Location /s
that works!

As #Bert Levrau mentioned above you can do a recursive search in CMD. Using Get-ChildItem in Powershell with a folder that has an ALT + 255 name will throw it into an infinite recursive loop. You can invoke a CMD process from Powershell though using the following example: $result = cmd /c $directoryPath /s
At that point, you can work through the result to find the information that you need.

Related

Powershell Set-Location Auto truncate spaces error

I want to write a batch file named install.bat that will run a Powershell script file install.ps1 as Administrator. The content of the batch file install.bat as simple as below:
#echo off
PowerShell -NoExit -Command "Start-Process PowerShell -Verb RunAs '-NoExit -Command "Set-Location ''%cd%''; .\install.ps1"'"
In this batch script, I call a Powershell to run the Start-Process command. This Start-Process command would invoke another Powershell as Administrator. The second Powershell would run Set-Location command to set working directory to %cd% then invoke the install.ps1 script. An error happens with the Set-Location command if i run the install.bat file from a folder with more than 1 consecutive space characters in its name, for example:
D:\New folder
install.bat script will run normally with folder has 1 space character in its name, for example:
D:\New folder
but if a folder has more than 1 consecutive space character like:
D:\New folder
then Set-Location will searching for folder:
D:\New folder
and will show this error incase D:\New folder does not exist:
Can anyone explain this error and give me a solution?
The first thing that I looked with your script was the various control characters (single-quotes, double-quotes, etc.). Nothing obvious stood out.
I looked for other examples, but double-spaces in path names is not necessarily a common occurrence.
So I poked around and did some tests in a Command Prompt box, created a comparable test directory, and checked to see what outputs I could get.
First I sent the Current Directory variable to a PowerShell command to echo the value:
C:\temp\test\test 123>powershell -Command "Write-Host %cd%"
The output had stripped one of the space characters from the path name as you had described (double-quotes added for clarity):
"C:\temp\test\test 123"
Then I tried it with the variable within single-quotes:
C:\temp\test\test 123>powershell -Command "Write-Host '%cd%'"
This output preserved the space characters of the path name correctly (double-quotes added for clarity):
"C:\temp\test\test 123"
Then I tried it with the variable within two pairs of single-quotes as you had used in your script:
C:\temp\test\test 123>powershell -Command "Write-Host ''%cd%''"
This output also stripped one of the space characters from the path name, and it also added a space character to the front of the returned value (double-quotes added for clarity):
" C:\temp\test\test 123"
So it seems that your script might get corrected by changing to one pair of single-quotes surrounding the Current Directory variable call instead of the two pairs of single-quotes.
I'm not sure if you had another purpose for using the two pairs of single-quotes, and I suppose that most processes might not care about the extra leading space on the value return.
I hope that this helps with your script.

Cannot find file path error for dir /b - Copying all file names script

I am trying to use a script that I've used before in Powershell, that is supposed to copy and paste all the file names inside a folder, into a text file.
I was able to use this script on a different computer last week, but can't do it now on my laptop.
Is there something I am not aware of?
The error it's giving is
Cannot find path 'C:\b' because it does not exist.
I tried removing the /b and I got a list of all the files but with other extra data like mode, last time write, length, name, and the extension of each file.
I really need the plain file name only. How can I do this? Thanks in advance!
the /b flag only works in cmd, not PowerShell
So you could try
cmd
dir /b
exit
Which will open CMD in your terminal and execute dir /b as a normal cmd command rather than PowerShell
Alternatively, just use PowerShell's Get-ChildItem (or gci for short)
To get just the plain file names using Get-ChildItem, you can do something like this:
# Assign the folder items to a variable $x
$x = gci
# Get only the names of those items
$x.name
See SS64 for details on CMD's dir and PowerShell's Get-ChildItem

Using windows command prompt in PowerShell - Network Drives

I'm having trouble moving from command prompt to powershell. Usually I hold the shift key while right clicking, select 'open command prompt here', and use dir /s>filename.txt to get a list of all files in a directory and its subfolders. However, my company just updated our computers and now I can't access the command prompt from the network folder I'm trying to get a directory list of.
When I right click and hold the shift key there is no option to 'open the command prompt' from the folder I'm selecting. I opened command prompt manually and attempted to navigate to the network folder, but no dice. I get an error regarding UNC (?) or that it basically can't do it because it's a network folder.
I attempted to use powershell the same way I use Command prompt given as an answer Here, however I get an error message
PS Microsoft.PowerShell.Core\FileSystem::\\my.company.com\companydata\MainProject\Records\Field Work\Invoices> dir /s >file.txt
dir : Cannot find path 's' because it does not exist.
At line:1 char:1
+ dir /s >file.txt
+ ~~~~~~~~~~~~~~~~
+ CategoryInfo : ObjectNotFound: (s:String) [Get-ChildItem], ItemNotFoundException
+ FullyQualifiedErrorId : PathNotFound,Microsoft.PowerShell.Commands.GetChildItemCommand
I also attempted to re-instate the command prompt option in the expanded right-click +shift key list as detailed here. However, I don't have the permissions required to run all the steps.
I just need a directory of everything in a specified network folder, just a list of all the files in the folder and subfolders: file paths, file names, and dates created. I used to be able to get it using command prompt but apparently, that's not available. I'm unsure how to use powershell, and help is much appreciated, in either getting new, simple, easy to understand powershell resources so I can teach myself, or in finding a work around so I can continue using command prompt.
Is there an interpretation guide I can use that goes from Command Prompt to Powershell, and also will let me list files in network drives? (I can sort of understand the current resources out there for having powershell list files in a directory on the computer, but what I need is the powershell to be able to list files in a specified network folder).
In powershell, dir is an alias for Get-ChildItem I believe you're getting that error because switches/arguments work differently in PowerShell. The first parameter by position is Path, so the system thinks you are providing the value /s for the path.
You can do this in PowerShell without having to launch cmd by leveraging Get-ChildItem. As you what the complete structure including the subfolders, user -Recurse
You could also export to csv instead of text file. There's a lot of data - Select can be used to restrict which fields you export.
$Path = "\\my.company.com\companydata\MainProject\Records\Field Work\Invoices"
$Files = Get-ChildItem -Path $Path -Recurse
$Files | Out-file file.txt
$Files | Select-Object FullName,CreationTime | Export-Csv file.csv -NoTypeInformation

How to call msys2 find command from PowerShell with correct shell escape characters?

I'm wondering how can I escape the following command from PowerShell so that it works?
PS C:\Users\buster\Documents\> find -name \*.c
PowerShell says: error not found *.c
PS C:\Users\buster\Documents\> find -name *.c
PowerShell says: error not found *.c
If you used find like that (without the full path) you most likely used the find.exe that ships with Windows (C:\Windows\system32\find.exe), which is more akin to grep than to Unix find. You get that behavior because Windows searches all directories in $env:PATH for files with the given name (and one of the extensions listed in $env:PATHEXT if no extension was specified), and executes the first match. Since %windir%\system32 is usually at the beginning of the PATH, executables from there take precedence.
You could add C:\msys64\msys64\usr\bin to the beginning of the PATH (before %windir%\system32), although I wouldn't recommend that. A better way would be to define an alias for the command:
New-Alias -Name 'find' -Value 'C:\msys64\msys64\usr\bin\find.exe'
Aliases take precedence over files. You could put the alias definition in your PowerShell profile so that it's automatically loaded whenever you start PowerShell.
Or you could simply use ls -r -fi '*.c' (short for Get-ChildItem -Recurse -Filter '*.c'), which would be the PowerShell way.
Ok false alarm..
Apparently its a case of windows having an executable with the same name as msys2's find.exe under c:\windows\system32 and the windows command getting higher priority in the path list. After explicitly typing out the full path to the msys64 version of find.exe it works.
PS C:\Users\buster\Documents\> C:\msys64\msys64\usr\bin\find -name \*.c
Also, Turns out there's a better way to find *.c files native to cmd.exe that you can call from powershell like this:
PS C:\Users\buster\Documents\> cmd /c dir /S /B *.v

PowerShell: Run command from script's directory

I have a PowerShell script that does some stuff using the script’s current directory. So when inside that directory, running .\script.ps1 works correctly.
Now I want to call that script from a different directory without changing the referencing directory of the script. So I want to call ..\..\dir\script.ps1 and still want that script to behave as it was called from inside its directory.
How do I do that, or how do I modify a script so it can run from any directory?
Do you mean you want the script's own path so you can reference a file next to the script? Try this:
$scriptpath = $MyInvocation.MyCommand.Path
$dir = Split-Path $scriptpath
Write-host "My directory is $dir"
You can get a lot of info from $MyInvocation and its properties.
If you want to reference a file in the current working directory, you can use Resolve-Path or Get-ChildItem:
$filepath = Resolve-Path "somefile.txt"
EDIT (based on comment from OP):
# temporarily change to the correct folder
Push-Location $dir
# do stuff, call ant, etc
# now back to previous directory
Pop-Location
There's probably other ways of achieving something similar using Invoke-Command as well.
There are answers with big number of votes, but when I read your question, I thought you wanted to know the directory where the script is, not that where the script is running. You can get the information with powershell's auto variables
$PSScriptRoot # the directory where the script exists, not the
# target directory the script is running in
$PSCommandPath # the full path of the script
For example, I have a $profile script that finds a Visual Studio solution file and starts it. I wanted to store the full path, once a solution file is started. But I wanted to save the file where the original script exists. So I used $PsScriptRoot.
If you're calling native apps, you need to worry about [Environment]::CurrentDirectory not about PowerShell's $PWD current directory. For various reasons, PowerShell does not set the process' current working directory when you Set-Location or Push-Location, so you need to make sure you do so if you're running applications (or cmdlets) that expect it to be set.
In a script, you can do this:
$CWD = [Environment]::CurrentDirectory
Push-Location $MyInvocation.MyCommand.Path
[Environment]::CurrentDirectory = $PWD
## Your script code calling a native executable
Pop-Location
# Consider whether you really want to set it back:
# What if another runspace has set it in-between calls?
[Environment]::CurrentDirectory = $CWD
There's no foolproof alternative to this. Many of us put a line in our prompt function to set [Environment]::CurrentDirectory ... but that doesn't help you when you're changing the location within a script.
Two notes about the reason why this is not set by PowerShell automatically:
PowerShell can be multi-threaded. You can have multiple Runspaces (see RunspacePool, and the PSThreadJob module) running simultaneously withinin a single process. Each runspace has it's own $PWD present working directory, but there's only one process, and only one Environment.
Even when you're single-threaded, $PWD isn't always a legal CurrentDirectory (you might CD into the registry provider for instance).
If you want to put it into your prompt (which would only run in the main runspace, single-threaded), you need to use:
[Environment]::CurrentDirectory = Get-Location -PSProvider FileSystem
This would work fine.
Push-Location $PSScriptRoot
Write-Host CurrentDirectory $CurDir
I often used the following code to import a module which sit under the same directory as the running script. It will first get the directory from which powershell is running
$currentPath=Split-Path ((Get-Variable
MyInvocation -Scope
0).Value).MyCommand.Path
import-module "$currentPath\sqlps.ps1"
I made a one-liner out of #JohnL's solution:
$MyInvocation.MyCommand.Path | Split-Path | Push-Location
Well I was looking for solution for this for a while, without any scripts just from CLI. This is how I do it xD:
Navigate to folder from which you want to run script (important thing is that you have tab completions)
..\..\dir
Now surround location with double quotes, and inside them add cd, so we could invoke another instance of powershell.
"cd ..\..\dir"
Add another command to run script separated by ;, with is a command separator in powershell
"cd ..\..\dir\; script.ps1"
Finally Run it with another instance of powershell
start powershell "cd..\..\dir\; script.ps1"
This will open new powershell window, go to ..\..\dir, run script.ps1 and close window.
Note that ";" just separates commands, like you typed them one by one, if first fails second will run and next after, and next after... If you wanna keep new powershell window open you add -noexit in passed command . Note that I first navigate to desired folder so I could use tab completions (you couldn't in double quotes).
start powershell "-noexit cd..\..\dir\; script.ps1"
Use double quotes "" so you could pass directories with spaces in names e.g.,
start powershell "-noexit cd '..\..\my dir'; script.ps1"