Windows Powershell scripts: Copy without node_modules and .next folders/directories; List node_modules and .next folders

Last updated on 10 Mar. 2025
5 Mar. 2025 Update
I am too squeezed for time to update this post. The latest scripts are available on my public GitHub repo: https://github.com/ravisiyer/PS-Scripts . Notes roughly after 5 Mar. 2025 are put up on MERN stack dev notes: Feb to Mar 2025 (includes Powershell scripts for copying and listing swdev project source code), https://raviswdev.blogspot.com/2025/02/mern-stack-dev-notes-feb-2025.html .
end- 5 Mar. 2025 Update

Quick-Info

CopyWoNmnx.ps1 Powershell script that copies contents of a folder/directory excluding node_modules and .next folders. It uses robocopy command to do the main work.

ListNmnx.ps1 Powershell script that lists node_modules and .next folders in a folder/directory. It ignores subfolders within the node_modules or .next folders it finds.

RemoveNmnxInCurDir.ps1 (very simple) Powershell script that deletes (after confirmation prompt) node_modules and .next folders in current directory after user confirmation for each folder delete. It does not go within subdirectories of current directory.

zListNRemoveNmnx.ps1 Powershell script that that lists and deletes (after confirmation prompt) node_modules and .next folders in a folder/directory. It goes into subfolders and is not limited to current directory. This script seems to be working in some limited tests I did. But it needs more testing before regular use. I don't have the time now for more testing.

CopyWoNmnx.ps1 Powershell script

My post: Using robocopy to copy folder without node_modules subfolder(s) and using WinMerge and TreeSize to check, Mar. 2024 covers how robocopy can be used to copy folder without node_modules subfolders. Adding .next to node_modules as a subfolder to be skipped in robocopy command is trivial.


CopyWoNmnx.ps1 is a convenience Powershell script that wraps above robocopy command usage. The script copies contents of a folder/directory excluding node_modules and .next folders. It uses robocopy command to do the main work.

Usage: script-name Source-Folder-Name

Output folder name is generated by concatenating script defined suffix (currently: -wo-nmnx) to Source-Folder-Name. The script checks if file/folder of this generated name exists and if so gives a suitable error message and then aborts.
The script also strips trailing backslash from Source-Folder-Name if present before generating output folder name. Note that Powershell adds trailing backslash by default to folder names when tab is used to step through files and folders being specified in a command on console.

ListNmnx.ps1 Powershell script


ListNmnx.ps1 script lists folders/directories with names matching script variable $ListFolders array elements (currently: node_modules and .next), in a user specified folder/directory or current directory. It also provides a total count of the folders it lists.
It ignores subfolders within the matching $ListFolders array elements (node_modules and .next) it finds. It also ignores folders present in script variable $ExcludeFolders array (currently: .git).

Usage: script-name [optional-path] 

The script uses Get-ChildItem calling it recursively.

RemoveNmnxInCurDir.ps1 Powershell script


This is a very simple script to delete NMNX folders in current directory after user confirmation for each folder delete. It does not go within subdirectories of current directory.

Usage: script-name

I felt the need for such simple script as I was deleting a large set of node_modules and, sometimes .next, folders. ListNmnx.ps1 did a good job of listing out the location of these folders. But to delete these folders I was doing it through Windows Explorer by navigating to the containing folder, then selecting the (NMNX) folder(s) using the mouse and then choosing to 'permanently' delete them. As I had to do it for many folders, ensuring that I do not mistakenly select a different folder and 'permanently' delete it was a serious concern. If I had a simple script like this, I could use Powershell console commands to navigate to the containing folder and then simply run this script. But I wrote the script and tested it with dummy data after I had finished my main deletion task with the earlier manual method. I had looked up the net to see how to do it while this deletion was going on and so I felt I should write the script now when this knowledge (syntax and cmdlet behaviour) was somewhat fresh in my mind. 

I also felt that limiting it to only current directory and not subdirectories and having the script as very simple code, significantly reduced the concern of the script mistakenly deleting some other directories which could be a disaster. So while this script is super simple, I think it is also safe even though I have done only limited testing.

zListNRemoveNmnx.ps1 Powershell script 

zListNRemoveNmnx.ps1 source code on GitHub Gist

I wish I had a very well tested and safe script that recursively deletes node_modules and .next folders as that would have been of great use to me in my task of deleting many node_modules and .next folders mentioned in above section, 'RemoveNmnxInCurDir.ps1 Powershell script'. In the past, if I recall correctly, I had seen if such a script was available for free on the Internet but could not get it. I thought I should make a quick try of modifying the ListNmnx.ps1 script which recursively lists NMNX directories, to additionally delete them (on confirmation from user for each such directory). After a few trip-ups, I was able to get such a modified script to work in some limited tests I did. But it surely needs more testing before regular use. I don't have the time now for more testing. Further, I really don't think I will have the time for thorough testing even in the near future at least, and that lack of thorough testing brings in an element of risk of using this script as it may mistakenly delete other folders besides NMNX folders.

But there may be some scenarios when I could try out this script like when I have a backup of a folder tree without NMNX folders and so I have a fallback if I delete non NMNX folders in a main folder tree. Maybe in future, I will use it in some scenarios and if it works well, I may develop more confidence in it.

As a safety mechanism, I am going with a confirmation prompt (that helped me already in testing as initial attempts to modify the script had a bug of attempting to delete the whole containing folder instead of only the NMNX subfolders in it!) Ideally I would like the default value in the confirmation prompt to be No instead of Yes as that would be a good safety feature. Sometimes pressing Enter on a keyboard may result in two 'Enters' and thus result in unwanted behaviour of the program. A combination of having to key in Y and then press Enter to proceed with the delete would be far more safe. But I could not figure out how to get Remove-Item cmdlet to use default of N instead of Y for its confirmation prompt.

Perhaps if I have a strong need for this script in future, I could invest time in having my own confirmation prompt where I could use default of N instead of using Remove-Item cmdlet's confirmation prompt. 

Usage: script-name [optional-path] 

Notes

These notes were made while writing the above scripts. These notes add to my previous Powershell related post: Windows PowerShell script and commands to list files and folders modified in past x days excluding specified folders like .git and node_modules, May 2024.
...
The following is an interesting post which provides a list all node_modules for command: 
How to Delete ALL node_modules folders on your machine and Free up HD space!, https://medium.com/@MarkPieszak/how-to-delete-all-node-modules-folders-on-your-machine-and-free-up-hd-space-f3954843aeda , Aug. 2019.

FOR /d /r . %d in (node_modules) DO @IF EXIST "%d" echo %d
lists all node_modules directories but they included sub directories within node_modules itself named node_modules. So output list is longer than what I ideally need which is only the first folder having node_modules and ignoring subfolders in node_modules.

This issue prompted me to explore writing ListNmnx.ps1 script.
...
...

Section "Param" in https://ss64.com/ps/syntax-args.html covers Param usage in PS. I could not locate a Param reference page in limited net search. So this article is very useful.







From: Capitalization guidelines (for PowerShell), https://github.com/PoshCode/PowerShellPracticeAndStyle/issues/36 :
  • Global Variable Names: $PascalCase
  • Local Variable Names: $camelCase 
  • Function Names: PascalCase
  • Function/method arguments: PascalCase
----
https://www.manageengine.com/products/desktop-central/returning-error-code-on-scripts-how-to.html states, "$LASTEXITCODE holds the last error code in the powershell script."

'write-host $LASTEXITCODE' or simply, '$LASTEXITCODE' on console prints out exit code of last command executed. 


Demo-Choices.ps1, https://gist.github.com/kpatnayakuni/da1c1d6e4d9b6e457727a9394af5170d shows how to prompt user with a choice in PS.


`n is used in Powershell to append a new line to the standard output.

The use of `n in Powershell is similar to \n in C++ or Java.
-----

Check if Arguments Exists in PowerShell, https://java2blog.com/check-if-arguments-exists-powershell/
==============

Use Write-Host or Write-Output in CopyWoNmnx.ps1 script?

I think Write-Host should be used as the script is simply an interactive front-end to the robocopy command that is executed if user chooses to proceed. If Write-Host is used then redirecting output to log.txt file by '.\copywonmnx.ps1 .\Test\ > log.txt' results in copywonmnx script interactions to be seen on console as is appropriate, and only robocopy output is redirected to log.txt. If Write-Output is used then only $host.UI.PromptForChoice data is shown on console, which I feel is too limited. So I have decided to stick to using Write-Host in CopyWoNmnx.ps1 script.

==================

Use Write-Host or Write-Output in ListNmnx.ps1 script?

The use may want to redirect the main output of this script to a file. So the main output statements should use Write-Output.

But usage message and debugging messages should go only to console and so they should use Write-Host.

I also wanted to get some exposure to Write-Error (writes to error stream) and so am using it for error messages. Note that error stream can be redirected to file by using 2> err.txt or similar. Example of full command redirecting output to log file and error to error file:
.\ListNmnx.ps1 xxx > log.txt 2> err.txt

========================

Variable scoping, recursion, and me - or - How do I accumulate a counter across recursive calls?, https://www.reddit.com/r/PowerShell/comments/agdk2w/variable_scoping_recursion_and_me_or_how_do_i/  ... explains how to increment a variable across recursions.
In my code, $ListFolderOccurrences++ within recursive function did not increment across recursions and final value I got was 0 (its initial value). Using $script:ListFolderOccurrences++ as suggested in a response in above article solved the issue with increment happening across recursions.
...
How to join String array into one String in PowerShell, https://morgantechspace.com/2021/01/how-to-join-string-array-into-one-string-in-powershell.html ... In my code, I used:
$NmnxFolders = $ListFolders -join ","
...
Using Write-Output to write a long string broken into two strings in source file, as one line. This is the code I am using:
"$ListFolderOccurrences folders found matching folder list: $NmnxFolders. " +
  "Note that subfolders within matched folders are ignored." | Write-Output
---
Comma separator results in multiple lines output.

============================

"Type Remove-Item -path C:\[Filename] and press Enter to permanently delete the file. Keep in mind you need to add the -recurse flag to the command if you want to delete a full directory and everything inside it." From https://www.avast.com/c-permanently-delete-files

Best and fast way to massive permanently delete - Windows - Spiceworks Community,

How to Delete a Folder in PowerShell? - SharePoint Diary,

directory - Powershell script to delete folders from list - Stack Overflow, https://stackoverflow.com/questions/9301986/powershell-script-to-delete-folders-from-list

How to save disk space taken by node modules?, https://codedamn.com/news/nodejs/save-disk-space-taken-by-node-modules

==========
Tried below cmd in PowerShell:
Remove-Item "node_modules"
It prompted for confirmation as follows (edited initial part of path):
Confirm
The item at C:\Users\...\TestPSScript\node_modules has children and the Recurse parameter
was not specified. If you continue, all children will be removed with the item. Are you sure you want to continue?
[Y] Yes  [A] Yes to All  [N] No  [L] No to All  [S] Suspend  [?] Help (default is "Y"):
--- end copy-paste ---
Pressing Enter deleted the directory.
An issue is that if the directory does not exist it gives an error message. Solution for that is to simple check for directory existence before delete:
If ( Test-Path "node_modules" ) { Remove-Item "node_modules" }
----

Interestingly, above Remove-Item command deletes the specified folder and files/folders within it permanently i.e. the deleted folder and its files/folders do not seem to go to recycle bin (I could not find it when I checked).
The articles below confirm the above.
Powershell Delete File If Exists, https://blog.netwrix.com/powershell-delete-file : "It is important to note that by default, items deleted with Remove-Item are permanently removed from the system and not sent to the Recycle Bin."
Deleting Files from CMD or Powershell and Recycle Bin, https://superuser.com/questions/1288978/deleting-files-from-cmd-or-powershell-and-recycle-bin : "When using command prompt or Powershell and the Remove-Item, del, or RD, why don't the items you delete end up in the recycle bin?". In this context, the question is the important point here and the answer is not important.
---

How can I change the default confirmation option for a PowerShell Cmdlet?, https://stackoverflow.com/questions/20061003/how-can-i-change-the-default-confirmation-option-for-a-powershell-cmdlet : 'I want to change the default from "Y" to "N".' This is what I want to do too. But the post does not have an answer.

Comments