I want to upload files to a file host using powershell cause it’s faster. The problem is it can’t read/open files that contain special character or non-english letter. Any fix for this? I want to avoid using Read/Write Node method
cause it’s slower especially if I’m dealing with large files
@Ruriko this is the same Windows OEM codepage issue from ur earlier tree-list question, just hitting a different surface. when n8n’s Execute Command node fires powershell on Windows Server, the command string travels through cmd.exe’s default codepage (usually 437 or 850 depending on system locale) which mangles UTF-8 paths before powershell ever sees them. so even tho the file exists on disk, powershell gets a garbled path string and can’t open it.
cleanest fix is to bypass cmd.exe’s parsing entirely using powershell’s -EncodedCommand flag. u base64-encode the full command as UTF-16LE first, then pass that to powershell.exe. since the encoded blob has no special chars, cmd.exe can’t mangle anything, and powershell decodes it natively into proper Unicode.
in n8n that looks like a Code node that builds the encoded command, then Execute Command that runs it:
two key details: use -LiteralPath instead of -Path in the powershell command (the literal version doesnt interpret wildcards or special chars), and the Buffer encoding must be utf16le (powershell expects UTF-16 LE, not UTF-8, for EncodedCommand).
alternative if u want to skip powershell entirely — use a Code node with node’s built-in fs.createReadStream + http upload. node handles UTF-8 paths natively on Windows since the runtime ignores Windows codepage. faster than spawning powershell too. happy to show that pattern if u want it.
@Ruriko looked at ur workflow JSON and theres three things stacking on each other.
first issue — ur using {{ $json.filepath }} INSIDE the JavaScript template literal in the Code node. thats n8n expression syntax which only works in n8n’s parameter UI, not inside Code node JS. inside Code node u use ${$json.filepath} (JS template literal). right now the literal text “{{ $json.filepath }}” is getting baked into the command, so curl is looking for a file called literally “{{ $json.filepath }}”.
second issue — Get-Item -LiteralPath ‘’ | curl.exe -F … doesnt do what u think. Get-Item’s pipe output is a FileInfo object, not file contents. curl doesnt read the file from that pipe at all. ur essentially running Get-Item, dropping the output, then running curl with the broken @path arg.
third issue — even if u fix both of those, curl.exe on Windows uses fopen() which is bound to the system codepage even after chcp 65001, so it would still choke on the Japanese characters in @path regardless of how clean ur EncodedCommand encoding is.
cleanest fix is to skip curl entirely and use powershell’s native Invoke-RestMethod which handles UTF-8 paths through .NET (not the system codepage):
what changed: swapped curl for Invoke-RestMethod -Form which handles multipart natively. Get-Item -LiteralPath now feeds a FileInfo object directly into -Form which becomes the file-upload part properly (so the file CONTENTS actually go through, not just the path string). escaped single quotes in case the filename has any (powershell’s escape rule is doubling: ’ becomes ‘’). added ConvertTo-Json so u get a parseable response back from the upload endpoint instead of formatted text.
then in the Execute Command node u keep what u already have: powershell.exe -NoProfile -EncodedCommand {{ $json.encoded }} — that {{ }} IS correct there since its in the n8n parameter UI, not JS code. the JS-vs-n8n-expression confusion is the trickiest part of mixing Code nodes and Execute Command nodes.
I think it now can read file but now I got a different error that it can’t find the parameter:
Command failed: powershell.exe -NoProfile -EncodedCommand JABmAG8AcgBtACAAPQAgAEAAewAgAHMAZQBzAHMAXwBpAGQAIAA9ACAAJwB4AHgAeAB4AHgAJwA7ACAAdQB0AHkAcABlACAAPQAgACcAcAByAGUAbQAnADsAIAB0AG8AXwBmAG8AbABkAGUAcgAgAD0AIAAnADIAOAA4ADkAMAAnADsAIABmAGkAbABlAF8AMAAgAD0AIABHAGUAdAAtAEkAdABlAG0AIAAtAEwAaQB0AGUAcgBhAGwAUABhAHQAaAAgACcAQwA6AFwAVQBzAGUAcgBzAFwAQQBkAG0AaQBuAGkAcwB0AHIAYQB0AG8AcgBcAEQAZQBzAGsAdABvAHAAXABPAFMAVABcAEMAbwBtAHAAbABlAHQAZQBcAFsAMgAwADIANgAuADAANQAuADIANQBdACAAZlsSV6IwpDDJMOsw3jC5ML8w/DAgAB1SH2ZmWxJXIABSAGUAbQBpAHgAIABBAGwAYgB1AG0ADDBSAGUAQwBvAGwAbABlAGMAdABpAG8AbgANMHYAbwBsAC4AMQAgAFsARgBMAEEAQwAgADQAOABrAEgAegAP/zIANABiAGkAdABdAC4AegBpAHAAJwAgAH0AOwAgAEkAbgB2AG8AawBlAC0AUgBlAHMAdABNAGUAdABoAG8AZAAgAC0AVQByAGkAIAAnAGgAdAB0AHAAcwA6AC8ALwBkADMAMAAwAC4AdQBzAGUAcgBkAHIAaQB2AGUALgBvAHIAZwAvAGMAZwBpAC0AYgBpAG4ALwB1AHAAbABvAGEAZAAuAGMAZwBpAD8AdQBwAGwAbwBhAGQAXwB0AHkAcABlAD0AZgBpAGwAZQAmAHUAdAB5AHAAZQA9AGEAbgBvAG4AJwAgAC0ATQBlAHQAaABvAGQAIABQAE8AUwBUACAALQBGAG8AcgBtACAAJABmAG8AcgBtACAAfAAgAEMAbwBuAHYAZQByAHQAVABvAC0ASgBzAG8AbgA=" #< CLIXML System.Management.Automation.PSCustomObjectSystem.Object1Preparing modules for first use.0-1-1Completed-1 1Preparing modules for first use.0-1-1Completed-1 Invoke-RestMethod : A parameter cannot be found that matches parameter name 'Form'._x000D__x000A_At line:1 char:343_x000D__x000A_+ ... in/upload.cgi?upload_type=file&utype=anon' -Method POST -Form $form | ..._x000D__x000A_+ ~~~~~_x000D__x000A_ + CategoryInfo : InvalidArgument: (:) [Invoke-RestMethod], ParameterBindingException_x000D__x000A_ + FullyQualifiedErrorId : NamedParameterNotFound,Microsoft.PowerShell.Commands.InvokeRestMethodCommand_x000D__x000A_ _x000D__x000A_
What is the Code node with node’s built-in fs.createReadStream + http upload method? does it require importing the binary file into n8n cause I don’t want that
Windows Server 2022 ships with PowerShell 5.1 as the default powershell.exe — and Invoke-RestMethod -Form only exists in PowerShell 7+. thats why ur getting the parameter error.
quickest fix is installing PowerShell 7 (called pwsh.exe, installs alongside the old one with zero conflict — its in the Microsoft store or GitHub - PowerShell/PowerShell: PowerShell for every system! · GitHub releases) and changing ur Execute Command from powershell.exe to pwsh.exe. everything else stays the same.
alternative if u dont want another PS install — skip powershell entirely and do the upload from an n8n Code node using Node’s fetch + FormData. n8n bundles its own Node so works regardless of Windows version. want the code for that path?
heres the Code node version — paste into a Code node set to “Run Once for All Items” mode, leave Execute Command unused since the upload runs directly from Node:
couple things worth knowing. fs.readFileSync loads the whole file into memory so for normal-sized files (under ~1GB) ur fine, but if ur FLAC album zip is bigger u’d want fs.createReadStream piped through the form-data package instead, lmk if u hit that case. fetch, FormData and Blob are all globals in n8n’s bundled Node so the only requires are fs and path. this also skips powershell entirely so the PS 5.1 / PS 7 issue just goes away — Node handles UTF-8 paths natively on Windows.
It doesn’t give any error in n8n but it doesn’t look like it’s actually uploading as it was just instant completed when I execute it. So I tried testing it in powershell instead of n8n to see if there were errors which results this:
ParserError:
Line |
2 | … e&utype=anon' -Method Post -ContentType \"multipart/form-data; bounda …
| ~~~~~~~~~~~~~~~~~~~
| Unexpected token 'multipart/form-data' in expression or statement.
ah right, the Code node sandbox doesnt expose Blob as a global even on Node 18+ — n8n whitelists globals strictly. and fs.readFileSync would OOM ur worker on 10gb anyway. use n8n’s bundled form-data npm package + raw https.request which streams without buffering anything into memory:
if u hit “Cannot find module form-data” or similar require error, set NODE_FUNCTION_ALLOW_EXTERNAL=form-data in ur n8n environment variables and restart. that whitelists the form-data package for the Code node sandbox — n8n 2.x defaults to no external modules for security. with that env var ur 10gb upload becomes bandwidth-bound, no memory copy of the file at all.
URL isnt exposed as a sandbox global either, same family as the Blob thing earlier. two ways to fix — add const { URL } = require(‘url’); at the top of the Code node, OR just drop the URL parsing entirely and hardcode hostname + path since u know the values: