Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Where is the "downloads" folder located

I'm making a script in Powershell ISE and to prevent piracy a part of the script needs to locates the file name and if it exists on the computer the script won't work. This will work cause downloading a file twice will give it a little (1).

I've google all kind of questions but I just really want to figure out the file path to a file located in downloads.

like image 819
Aleks_leeks Avatar asked Sep 12 '25 16:09

Aleks_leeks


2 Answers

tl;dr

  • The naive[1] answer, which typically but not always works:
"$HOME\Downloads"
  • The robust answer:
(New-Object -ComObject Shell.Application).NameSpace('shell:Downloads').Self.Path

"$HOME\Downloads" assumes two things, which aren't necessarily true:

  • That $HOME, which is equivalent to environment variable USERPROFILE ($env:USERPROFILE), is the root directory for the user's documents isn't always true, namely not with roaming profiles - only "${env:HOMEDRIVE}${env:HOMEPATH}" reliably reflects the documents folder.

  • More importantly, the downloads folder may have been explicitly configured to be in an arbitrary location, unrelated to the documents location

The only robust way to determine the downloads folder's location is to ask the system for it:

PowerShell, as of PowerShell (Core) 7 v7.4.x, has no PowerShell-native way of asking the system for known folder locations.

  • Adding such a feature has been proposed in GitHub issue #6966, however.

While PowerShell has virtually unlimited access to the .NET framework and can therefore use the System.Environment type's .GetFolderPath() method to ask for special known folders (e.g. [Environment]::GetFolderPath('Desktop')), asking for the downloads folder, specifically, is not supported, surprisingly, as of .NET 9.

Only the WinAPI's Known Folders API allows retrieval of the designated downloads folders in a robust fashion, without relying on fixed relationships with other known folders:

In PowerShell, you can access it via the Shell.Application COM server:

(New-Object -ComObject Shell.Application).NameSpace('shell:Downloads').Self.Path

For a list of all supported (shell:-prefixed) folder identifiers, see this article.


[1] By naive I mean: a solution that one is understandably tempted to use, but which doesn't work in all situations.

like image 167
mklement0 Avatar answered Sep 15 '25 10:09

mklement0


Using Windows API:

function Get-DownloadFolderPath() {
    $SHGetKnownFolderPathSignature = @'
    [DllImport("shell32.dll", CharSet = CharSet.Unicode)]
    public extern static int SHGetKnownFolderPath(
        ref Guid folderId,
        uint flags,
        IntPtr token,
        out IntPtr lpszProfilePath);
'@

    $GetKnownFoldersType = Add-Type -MemberDefinition $SHGetKnownFolderPathSignature -Name 'GetKnownFolders' -Namespace 'SHGetKnownFolderPath' -Using "System.Text" -PassThru
    $folderNameptr = [intptr]::Zero
    [void]$GetKnownFoldersType::SHGetKnownFolderPath([Ref]"374DE290-123F-4565-9164-39C4925E467B", 0, 0, [ref]$folderNameptr)
    $folderName = [System.Runtime.InteropServices.Marshal]::PtrToStringUni($folderNameptr)
    [System.Runtime.InteropServices.Marshal]::FreeCoTaskMem($folderNameptr)
    $folderName
}

$downloadFolderPath = Get-DownloadFolderPath
write-host "Download folder path: $($downloadFolderPath)"

Original version using Registry:

$downloadFolderPath = (Get-ItemProperty -Path "HKCU:\SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\Shell Folders").PSObject.Properties["{374DE290-123F-4565-9164-39C4925E467B}"].Value
like image 36
zumalifeguard Avatar answered Sep 15 '25 09:09

zumalifeguard