PowerShell 5 introduces the New-TemporaryFile
cmdlet, which is handy. How can I do the same thing but instead of a file create a directory? Is there a New-TemporaryDirectory
cmdlet?
I think it can be done without looping by using a GUID for the directory name:
function New-TemporaryDirectory {
$parent = [System.IO.Path]::GetTempPath()
[string] $name = [System.Guid]::NewGuid()
New-Item -ItemType Directory -Path (Join-Path $parent $name)
}
Original Attempt With GetRandomFileName
Here's my port of this C# solution:
function New-TemporaryDirectory {
$parent = [System.IO.Path]::GetTempPath()
$name = [System.IO.Path]::GetRandomFileName()
New-Item -ItemType Directory -Path (Join-Path $parent $name)
}
Analysis Of Possibility Of Collision
How likely is it that GetRandomFileName
will return a name that already exists in the temp folder?
- Filenames are returned in the form
XXXXXXXX.XXX
where X can be either a lowercase letter or digit. - That gives us 36^11 combinations, which in bits is around 2^56
- Invoking the birthday paradox, we'd expect a collision once we got to around 2^28 items in the folder, which is about 360 million
- NTFS supports about 2^32 items in a folder, so it is possible to get a collision using
GetRandomFileName
NewGuid
on the other hand can be one of 2^122 possibilities, making collisions all but impossible.
-Force
to create non-existent parent dirs, but I was wrong, so I updated the answer. –
Bernicebernie $name = (New-Guid).ToString('n')
, which creates a string like 450d881de6054d5894c7f7378bbb9f51
. –
Rubicon Return (New-Item -ItemType Directory -Path (Join-Path $parent $name)).FullName
–
Malave I also love one-liners, and I'm begging for a downvote here. All I ask is that you put my own vague negative feelings about this into words.
New-TemporaryFile | %{ rm $_; mkdir $_ }
Depending on the type of purist you are, you can do %{ mkdir $_-d }
, leaving placeholder to avoid collisions.
And it's reasonable to stand on Join-Path $env:TEMP $(New-Guid) | %{ mkdir $_ }
also.
New-TemporaryFile | % { Remove-Item $_; New-Item -ItemType Directory -Path $_ }
–
Prejudicial -d
doesn't avoid collisions. (What if you're using the same approach in two different scripts at the same time?) But then, you weren't trying to avoid collisions, were you? ;-) –
Saturate -d
is to avoid a so-called “collision” between the resulting file and directory. –
Rahmann New-TemporaryFile | %{ rm $_; mkdir "${_}d" }
. –
Adipose Here's a variant of user4317867's answer. I create a new directory in the user's Windows "Temp" folder and make the temp folder path available as a variable ($tempFolderPath
):
$tempFolderPath = Join-Path $Env:Temp $(New-Guid)
New-Item -Type Directory -Path $tempFolderPath | Out-Null
Here's the same script available as a one-liner:
$tempFolderPath = Join-Path $Env:Temp $(New-Guid); New-Item -Type Directory -Path $tempFolderPath | Out-Null
And here's what the fully qualified temp folder path ($tempFolderPath
) looks like:
C:\Users\MassDotNet\AppData\Local\Temp\2ae2dbc4-c709-475b-b762-72108b8ecb9f
If you want the looping solution that is guaranteed to be both race- and collision-free, then here it is:
function New-TemporaryDirectory {
$parent = [System.IO.Path]::GetTempPath()
do {
$name = [System.IO.Path]::GetRandomFileName()
$item = New-Item -Path $parent -Name $name -ItemType "directory" -ErrorAction SilentlyContinue
} while (-not $item)
return $item.FullName
}
According to the analysis in Michael Kropat's answer, the vast majority of the time, this will pass only once through the loop. Rarely will it pass twice. Virtually never will it pass three times.
Here's my attempt:
function New-TemporaryDirectory {
$path = Join-Path ([System.IO.Path]::GetTempPath()) ([System.IO.Path]::GetRandomFileName())
#if/while path already exists, generate a new path
while(Test-Path $path)) {
$path = Join-Path ([System.IO.Path]::GetTempPath()) ([System.IO.Path]::GetRandomFileName())
}
#create directory with generated path
New-Item -ItemType Directory -Path $path
}
while
and the New-Item
command. –
Michikomichon .NET has had [System.IO.Path]::GetTempFileName()
for quite a while; you can use this to generate a file (and the capture the name), then create a folder with the same name after deleting the file.
$tempfile = [System.IO.Path]::GetTempFileName();
remove-item $tempfile;
new-item -type directory -path $tempfile;
$tempfilename
used ? –
Kakemono I love one liners if possible. @alroc .NET also has [System.Guid]::NewGuid()
$temp = [System.Guid]::NewGuid();new-item -type directory -Path d:\$temp
Directory: D:\
Mode LastWriteTime Length Name
---- ------------- ------ ----
d---- 1/2/2016 11:47 AM 9f4ef43a-a72a-4d54-9ba4-87a926906948
$temp = New-Item -Type Directory -Path $env:TEMP -Name ([System.Guid]::NewGuid())
–
Maulmain if you want, you can be extremely fancy and call Windows API function GetTempPathA()
like this:
# DWORD GetTempPathA(
# DWORD nBufferLength,
# LPSTR lpBuffer
# );
$getTempPath = @"
using System;
using System.Runtime.InteropServices;
using System.Text;
public class getTempPath {
[DllImport("KERNEL32.DLL", EntryPoint = "GetTempPathA")]
public static extern uint GetTempPath(uint nBufferLength, [Out] StringBuilder lpBuffer);
}
"@
Add-Type $getTempPath
$str = [System.Text.StringBuilder]::new()
$MAX_PATH = 260
$catch_res = [getTempPath]::GetTempPath($MAX_PATH, $str)
Write-Host $str.ToString() #echos temp path to STDOUT
# ... continue your code here and create sub folders as you wish ...
Path.GetTempPath
does for you internally. –
Quipster Expanding from Michael Kropat's answer: https://mcmap.net/q/279153/-create-a-temporary-directory-in-powershell
Function New-TemporaryDirectory {
$tempDirectoryBase = [System.IO.Path]::GetTempPath();
$newTempDirPath = [String]::Empty;
Do {
[string] $name = [System.Guid]::NewGuid();
$newTempDirPath = (Join-Path $tempDirectoryBase $name);
} While (Test-Path $newTempDirPath);
New-Item -ItemType Directory -Path $newTempDirPath;
Return $newTempDirPath;
}
This should eliminate any issues with collisions.
while
and the New-Item
command, exactly as the other answer above. –
Michikomichon © 2022 - 2024 — McMap. All rights reserved.
GetRandomFileName()
andNew-Item
in a loop to automatically retry in case of a name conflict. – Buckjump