I can't recursively remove the pyc files from my Python project.
Here is the project:
Directory: C:\Users\jk025523\projects\ex47
Mode LastWriteTime Length Name
---- ------------- ------ ----
d----- 10/07/2016 01:52 bin
d----- 10/07/2016 01:52 docs
d----- 10/07/2016 01:52 ex47
d----- 10/07/2016 01:52 tests
-a---- 09/07/2016 21:02 521 setup.py
There are indeed some pyc files inside the tests directory:
Directory: C:\Users\jk025523\projects\ex47\tests
Mode LastWriteTime Length Name
---- ------------- ------ ----
-a---- 09/07/2016 21:28 180 ex47_tests.py
-a---- 09/07/2016 21:28 721 NAME_tests.pyc
-a---- 05/07/2016 10:52 0 __init__.py
-a---- 05/07/2016 11:37 140 __init__.pyc
However when I enter this command in PowerShell to remove all the pyc files:
find . -name "*.pyc" -exec rm -rf {}
PowerShell outputs this error:
FIND: Parameter format not correct
Anybody know how I can remove all the pyc files from this Python project?
The command you're trying to use is the Linux/Unix find command, which doesn't work on Windows (unless you have something like Cygwin installed, which I don't recommend). Windows has a command with the same name, but different functionality (works more like grep). PowerShell does not have a find cmdlet or alias. You'd do recursive deletion of files with a particular extension like this in PowerShell:
Get-ChildItem -Filter '*.pyc' -Force -Recurse | Remove-Item -Force
If the "find" command you are running is of the linux/unix equivalent, your --exec rm -rf {} will need a delimiter at the end. Like so:
find . -name "*.pyc" -exec rm -rf "{}" \;
I would also recommend always wrapping the variable brackets ({}) in quotes to ensure you are not deleting more than what you are trying to delete.
EDIT: Looks like you are using the Windows find variant, which does not support the arguments you are attempting to use. You can see this page for syntax examples.
You may want to look at one of these answers for alternatives.
Related
I'm trying to develop a quite simple so called SendLet. It consists of a PowerShell script that is run by a Send to shortcut from the context menu in the Windows Explorer. Invoked on arbitrary files or folders these are given as argumets to the script. My approach ist the following:
SendLet.ps1
param (
[Parameter(ValueFromRemainingArguments=$true)]
$FilePath
)
Get-ChildItem -Recurse -Path $FilePath | ForEach-Object {
Write-Host $_
}
Pause
Arbitrary Files
PowerShell 7.3.2
PS C:\Users\user\Desktop\Arbitrary Files> Get-ChildItem
Directory: C:\Users\user\Desktop\Arbitrary Files
Mode LastWriteTime Length Name
---- ------------- ------ ----
-a--- 29.01.2023 16:44 276246528 Baz qux.AVI
-a--- 29.01.2023 16:44 3787047 Foo bar.JPG
PS C:\Users\user\Desktop\Arbitrary Files>
Setup
Save the SendLet script as C:\Users\user\Documents\PowerShell\Scripts\SendLet.ps1
Create a shortcut in shell:sendto (e.g. as C:\Users\user\AppData\Roaming\Microsoft\Windows\SendTo\SendLet.lnk) with the target being C:\Users\user\AppData\Local\Microsoft\WindowsApps\pwsh.exe C:\Users\user\Documents\PowerShell\Scripts\SendLet.ps1.
Send arbitrary files or folders to the script through the Send to context menu.
Run
Runing the above described approach on my Windows 11 22H2 machine results in the follwing output:
C:\Users\user\Desktop\Arbitrary Files\Baz qux.AVI
C:\Users\user\Desktop\Arbitrary Files\Foo bar.JPG
Press Enter to continue...:
Meaning: Two files with absolute path found to process...
However, running the very same approach on my Windows 10 Pro 22H2 machine results in the following error:
Get-ChildItem: D:\Users\user\Documents\PowerShell\Scripts\SendLet.ps1:6
Line |
6 | Get-ChildItem -Recurse -Path $FilePath | ForEach-Object {
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
| Cannot find path 'D:\Users\user\Documents\PowerShell\Scripts\Files\' because it does not exist.
Get-ChildItem: D:\Users\user\Documents\PowerShell\Scripts\SendLet.ps1:6
Line |
6 | Get-ChildItem -Recurse -Path $FilePath | ForEach-Object {
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
| Cannot find path 'D:\Users\user\Documents\PowerShell\Scripts\Files\' because it does not exist.
Press Enter to continue...:
The path being complained about in the error message is completely wrong and not existent. That's why it does not exist! So the error message itself is correct. But why does the script look for a wrong path argument? I suppose the argument quoting is not working properly.
/UPDATE: The only difference I can see is that the test data is placed in C: drive of my working machine. On my failing machine the test data is placed in D: drive, instead. But why should this matter?
/UPDATE 2: Now, I tested to place the test data on C: drive of my failing machine. Strangely all is working!? So, my SendLet works on files or folder in C: but not D: drive :-(
/UPDATE 3: I tested the both scripts suggested by #zett42 as solution. The outcome is a little bit odd.
Run on the Arbitrary Files folder (metioned above) on my working Windows 11 machine, the second script prints:
Processing file: C:\Users\user\Desktop\Arbitrary Files\Baz qux.AVI
Processing file: C:\Users\user\Desktop\Arbitrary Files\Foo bar.JPG
Press Enter to continue...:
The second script run on the two contained files prints:
Processing file: C:\Users\user\Desktop\Arbitrary Files\Baz qux.AVI
Processing file: C:\Users\user\Desktop\Arbitrary Files\Foo bar.JPG
Press Enter to continue...:
So far so good... And now the same on my problematic Windows 10 Pro machine.
The second script run onto the folder prints:
Processing file: D:\Users\user\Desktop\Arbitrary
Processing file: Files
Press Enter to continue...:
Run directly on the two contained files it prints:
Processing file: D:\Users\user\Desktop\Arbitrary
Processing file: Files\Baz
Processing file: qux.AVI
Processing file: D:\Users\user\Desktop\Arbitrary
Processing file: Files\Foo
Processing file: bar.JPG
Press Enter to continue...:
What is this? What is going on with my Windows 10 Pro machine?
It seems like my Windows 11 machine runs the PowerShell script on the folder with arguments as "C:\Users\user\Desktop\Arbitrary Files". See one quoted argument containing whitespaces.
However, my Windows 10 Pro machine seems to run the script on the folder with arguments as C:\Users\user\Desktop\Arbitrary Files, resulting in two arguments seperated by a whitespace.
Same behaviour seems to apply to the script run directly on the two test files in the folder as quoted arguments:
"C:\Users\user\Desktop\Arbitrary Files\Baz qux.AVI" "C:\Users\user\Desktop\Arbitrary Files\Foo bar.JPG" => Two quoted arguments
... or unquoted arguments:
C:\Users\user\Desktop\Arbitrary Files\Baz qux.AVI C:\Users\user\Desktop\Arbitrary Files\Foo bar.JPG => 6 unquoted arguments
This cannot be a normal behaviour. Or is it?
Maybe there is something I am missing? Any suggestions?
/UPDATE 4: I found the problem -__- which turns out to be very, very annoying... Once again I was inspecting the SendTo-Links on both my machines. The only difference was the absolute path to the interpreter pwsh.exe, because PowerShell was installed differently.
On the good machine the path to pwsh.exe points to C:\Program Files\PowerShell\7\pwsh.exe. So far so good.
On the problematic machine the path pointing to pwsh.exe was C:\Users\user\AppData\Local\Microsoft\WindowsApps\pwsh.exe, instead. So what, I was thinking. It's just a different path. But as I opened the folder in the explorer, I got suspicious because the pwsh.exe file has a size of 0 bytes :-O Then I opened the very same folder in a PowerShell Terminal and typed ls, to reveal something I was not expecting. All the EXE files in there are just links to somewhere else, but I don't know where to? Whar are the arrows -> meaning?
PowerShell 7.3.2
PS C:\Users\user\AppData\Local\Microsoft\WindowsApps> ls
Directory: C:\Users\user\AppData\Local\Microsoft\WindowsApps
Mode LastWriteTime Length Name
---- ------------- ------ ----
d---- 10.01.2023 18:44 Backup
d---- 25.01.2023 10:57 Microsoft.DesktopAppInstaller_8wekyb3d8bbwe
d---- 20.12.2022 11:50 Microsoft.MicrosoftEdge_8wekyb3d8bbwe
d---- 28.01.2023 23:08 Microsoft.PowerShell_8wekyb3d8bbwe
d---- 26.01.2023 17:18 Microsoft.SkypeApp_kzf8qxf38zg5c
d---- 28.01.2023 14:19 Microsoft.WindowsTerminal_8wekyb3d8bbwe
d---- 10.02.2023 10:50 Microsoft.XboxGamingOverlay_8wekyb3d8bbwe
d---- 03.02.2023 15:55 SpotifyAB.SpotifyMusic_zpdnekdrzrea0
la--- 10.02.2023 10:50 0 GameBarElevatedFT_Alias.exe ->
la--- 20.12.2022 11:50 0 MicrosoftEdge.exe ->
la--- 28.01.2023 23:08 0 pwsh.exe ->
la--- 25.01.2023 10:57 0 python.exe ->
la--- 25.01.2023 10:57 0 python3.exe ->
la--- 26.01.2023 17:18 0 Skype.exe ->
la--- 03.02.2023 15:55 0 Spotify.exe ->
la--- 25.01.2023 10:57 0 WindowsPackageManagerServer.exe ->
la--- 25.01.2023 10:57 0 winget.exe ->
la--- 28.01.2023 14:19 0 wt.exe ->
PS C:\Users\user\AppData\Local\Microsoft\WindowsApps>
As I conclude, the very issue here is, that ALL THE arguments passed to the interpreter-link are not passed correctly (quotage gets lost) to the PowerShell interpreter!
Setting up my SendLet pointing to the interpreter itself, instead of a link, solved my issue.
Thanks to #all
I don't think you are supposed to pass file paths with -recurse switch to Get-ChildItem. At least I get strange behavior in that the directory containing the file is enumerated, even if I pass only a single file via SendTo menu. Apart from that, the script receives all paths correctly, regardless of spaces and location on disk drives.
So to make sure Get-ChildItem behaves as expected, first loop over the paths received as arguments and test which one actually is a directory. Also, make sure to call Get-ChildItem with parameter -File if you only want to iterate files.
param (
[Parameter(ValueFromRemainingArguments=$true)]
$FilePath
)
foreach( $path in $FilePath ) {
if( (Test-Path $path -PathType Container) ) {
"Is directory: $path"
Get-ChildItem -Recurse -File -Path $path | ForEach-Object {
$_
}
}
else {
"Is file: $path"
}
}
Pause
Note that I have removed Write-Host because it is not needed. Unassigned expressions are considered as implicit output by PowerShell.
Though for better structure, I would wrap the file enumeration code into a function.
param (
[Parameter(ValueFromRemainingArguments=$true)]
$FilePath
)
# A function that outputs only file paths, regardless if file
# paths or directory paths are passed. Directories are processed recursively.
Function EnumerateFilesRecursive( [string[]] $FileOrDirectoryPaths ) {
foreach( $path in $FileOrDirectoryPaths ) {
if( (Test-Path $path -PathType Container) ) {
Get-ChildItem -Recurse -File -Path $path | ForEach-Object Fullname
}
else {
$path
}
}
}
# Call the function and process its output (file paths)
EnumerateFilesRecursive $FilePath | ForEach-Object {
"Processing file: $_"
}
pause
Here I answer my own question based on /UPDATE 4 (see above) of the like.
Pay attention to which PowerShell interpreter's EXE file your Send to shortcut (placed inside shell:SendTo) is pointing to. Whether it is the genuine EXE file (i.e. pwsh.exe for version 7) or a symbolic link to that? It turns out, sending file arguments to the symbolic link does not handle paths containing white-spaces, at all!
One can recognize a symbolic link by its size of 0 bytes in the Windows explorer or by an right arrow -> printed by the ls command in the PowerShell's terminal.
PowerShell 7.3.2
PS C:\Users\user\AppData\Local\Microsoft\WindowsApps> ls
Directory: C:\Users\user\AppData\Local\Microsoft\WindowsApps
Mode LastWriteTime Length Name
---- ------------- ------ ----
d---- 10.01.2023 18:44 Backup
d---- 25.01.2023 10:57 Microsoft.DesktopAppInstaller_8wekyb3d8bbwe
d---- 20.12.2022 11:50 Microsoft.MicrosoftEdge_8wekyb3d8bbwe
d---- 28.01.2023 23:08 Microsoft.PowerShell_8wekyb3d8bbwe
d---- 26.01.2023 17:18 Microsoft.SkypeApp_kzf8qxf38zg5c
d---- 28.01.2023 14:19 Microsoft.WindowsTerminal_8wekyb3d8bbwe
d---- 10.02.2023 10:50 Microsoft.XboxGamingOverlay_8wekyb3d8bbwe
d---- 03.02.2023 15:55 SpotifyAB.SpotifyMusic_zpdnekdrzrea0
la--- 10.02.2023 10:50 0 GameBarElevatedFT_Alias.exe ->
la--- 20.12.2022 11:50 0 MicrosoftEdge.exe ->
la--- 28.01.2023 23:08 0 pwsh.exe ->
la--- 25.01.2023 10:57 0 python.exe ->
la--- 25.01.2023 10:57 0 python3.exe ->
la--- 26.01.2023 17:18 0 Skype.exe ->
la--- 03.02.2023 15:55 0 Spotify.exe ->
la--- 25.01.2023 10:57 0 WindowsPackageManagerServer.exe ->
la--- 25.01.2023 10:57 0 winget.exe ->
la--- 28.01.2023 14:19 0 wt.exe ->
PS C:\Users\user\AppData\Local\Microsoft\WindowsApps>
I have a folder in windows that's name is RESIDENCES INC.. The problem is this is actually an invalid foldername because of the period in it. If I try to delete it, it says
Could not find this item. This is no longer located in <path to folder>. Verify the item's location and try again.
How can I remove it with code?
That's weird, might be a Windows thing? It worked fine for me:
PS /home/Documents/test> mkdir "RESIDENCES INC."
PS /home/Documents/test> gi './RESIDENCES INC./'
Directory: /home/Documents/test
Mode LastWriteTime Length Name
---- ------------- ------ ----
d---- 3/18/2021 12:04 AM RESIDENCES INC.
PS /home/Documents/test> (gi './RESIDENCES INC./').FullName
/home/Documents/test/RESIDENCES INC./
PS /home/Documents/test> Remove-Item (gi './RESIDENCES INC./').FullName -Force
PS /home/Documents/test> (gi './RESIDENCES INC./').FullName
Get-Item: Cannot find path '/home/Documents/test/RESIDENCES INC./' because it does not exist.
PS /home/Documents/test>
Can you paste the command you're using to delete the folder?
I'm creating a binary PS module with PlatyPS help. I have a local poor-man's deploy script like this (PS 5.1):
$modulepath= "$Env:USERPROFILE\Documents\WindowsPowerShell\Modules"
$releasePath = ".\bin\release\net472"
# build project
dotnet build -c release
# build documentation
# requires PlatyPS module
New-ExternalHelp -Path .\docs -OutputPath $releasePath\en-US -Force
ls $releasePath # debug
# copy files
Get-ChildItem -Path $releasePath | Copy-Item -Destination $modulepath\PoshCommence -Recurse -Force
ls $modulepath\PoshCommence # debug
This ouputs the following surprising result:
Directory: X:\CustomModules\PoshCommence\bin\release\net472
Mode LastWriteTime Length Name
---- ------------- ------ ----
d----- 17-2-2021 00:31 en-US
-a---- 17-2-2021 00:24 36352 PoshCommence.dll
Directory: C:\Users\XXX\Documents\WindowsPowerShell\Modules\PoshCommence
Mode LastWriteTime Length Name
---- ------------- ------ ----
-a---- 17-2-2021 00:31 871 about_PoshCommence.help.txt <- from en-US folder
-a---- 17-2-2021 00:24 36352 PoshCommence.dll
-a---- 17-2-2021 00:31 141080 PoshCommence.dll-Help.xml <- from en-US folder
None of the directories exist prior to running the script. I deleted the 'bin' project folder as well as the 'PoshCommence' module folder.
It seems either Get-ChildItem or Copy-Item -Recurse do not pick up the newly created 'en-US' directory, but the contents of it do get copied to the root level. If I run the script a second time (without deleting folders), it works as expected (except I still have docs stuff in the root of the module I don't want).
That has me stumped. I have tried -Verbose on everything, I put Start-Sleep after every line thinking operations may need time, but to no avail. Why isn't the 'en-US' folder picked up the first time?
Answering my own question. My confusion stems from the fact that
Copy-Item -Path $source -Destination $destination -Recurse
Works differently depending on whether the folder in $destination already exists or not.
So in the end all it took was
if (!(Test-Path $modulepath\PoshCommence)) { mkdir $modulepath\PoshCommence }
prior to the copying.
I've been trying to move a file using Microsoft Powershell,
I've looked on the Microsoft website and didn't understand the instructions.
Here is the directory contents as shown by Get-ChildItem:
Directory: C:\Users\Username\lpthw
Mode LastWriteTime Length Name
---- ------------- ------ ----
d----- 5/19/2020 6:38 PM useful
-a---- 5/9/2020 2:08 PM 263 drill5.py
Q: I would like to know how I can move the file drill5.py to the directory useful.
https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.management/move-item?view=powershell-7
Move-Item -Path .\drill5.py -Destination .\useful\
# Another way. mv is an alias for Move-Item
mv .\drill5.py .\useful\
I am currently writing a little script/program that will identify and sort certain files in a Windows directory. I am using the ls -n command to output a list of files to later be used by grep for Windows. However, using the following command:
ls -n >test.txt
leaves off the file extensions for file names in the output file. When I use ls -n inside the Powershell console (no output redirection), the file extensions are in the output.
Does anyone know what the issue is or how to do this properly with Powershell?
This works fine for me:
PS C:\Users\fission\Desktop\test> dir
Directory: C:\Users\fission\Desktop\test
Mode LastWriteTime Length Name
---- ------------- ------ ----
-a--- 2011-06-19 3:22 PM 1250 capture.pcap
-a--- 2013-09-26 5:21 PM 154205 fail.pml
-a--- 2013-09-25 12:53 PM 1676383 hashfxn.exe
PS C:\Users\fission\Desktop\test> ls -n >test.txt
PS C:\Users\fission\Desktop\test> type test.txt
capture.pcap
fail.pml
hashfxn.exe
test.txt
As you can see, test.txt includes the extensions of the other files.
But may I make a suggestion? Piping text output to a file, then grepping it isn't very "idiomatic" in PowerShell. It's a bit counter to a central theme of PowerShell: one should pass objects, not text. You might consider working with the output of Get-ChildItem directly, eg by storing it in a variable, or piping it to Select-Object, etc.
Don't use aliases in scripts, because you can't depend upon them being set the same everywhere.
This will get you a listing of all files (and no directories) in the current directory, sort it alphabetically, and write it to test.txt.
Get-ChildItem |
where-object (!$_.PSIsContainer}|
select-object -expandproperty Name|
sort-object | out-file test.txt
If you're searching for strings within those files, you can use select-string instead of grep, to keep it completely within PowerShell.
Get-ChildItem |
where-object (!$_.PSIsContainer}|
select-string PATTERN