49

PowerShell 5 引入了New-TemporaryFilecmdlet,非常方便。我怎样才能做同样的事情,而不是文件创建一个目录?有New-TemporaryDirectorycmdlet 吗?

4

9 回答 9

70

我认为它可以通过使用目录名称的 GUID 来完成而无需循环:

function New-TemporaryDirectory {
    $parent = [System.IO.Path]::GetTempPath()
    [string] $name = [System.Guid]::NewGuid()
    New-Item -ItemType Directory -Path (Join-Path $parent $name)
}

使用 GetRandomFileName 的原始尝试

这是我对这个 C# 解决方案的移植:

function New-TemporaryDirectory {
    $parent = [System.IO.Path]::GetTempPath()
    $name = [System.IO.Path]::GetRandomFileName()
    New-Item -ItemType Directory -Path (Join-Path $parent $name)
}

碰撞可能性分析

GetRandomFileName返回临时文件夹中已经存在的名称的可能性有多大?

  • XXXXXXXX.XXX文件名以X 可以是小写字母或数字的形式返回。
  • 这给了我们 36^11 种组合,以位为单位约为 2^56
  • 调用生日悖论,我们预计一旦文件夹中有大约 2^28 个项目,即大约 3.6 亿个,就会发生冲突
  • NTFS 在一个文件夹中支持大约 2^32 个项目,因此使用它可能会发生冲突GetRandomFileName

NewGuid另一方面,可能是 2^122 种可能性之一,这使得碰撞几乎是不可能的。

于 2016-01-01T19:59:35.177 回答
30

我也喜欢单线,我请求在这里投反对票。我所要求的只是你把我自己对此模糊的负面感受用语言表达出来。

New-TemporaryFile | %{ rm $_; mkdir $_ }

根据您是纯粹主义者的类型,您可以这样做%{ mkdir $_-d },留下占位符以避免碰撞。

站着也是合理的Join-Path $env:TEMP $(New-Guid) | %{ mkdir $_ }

于 2017-01-16T20:36:34.063 回答
13

这是 user4317867 的答案的变体。我在用户的 Windows“ Temp ”文件夹中创建了一个新目录,并将临时文件夹路径作为变量 ( $tempFolderPath) 提供:

$tempFolderPath = Join-Path $Env:Temp $(New-Guid)
New-Item -Type Directory -Path $tempFolderPath | Out-Null

这是可用作单行的相同脚本:

$tempFolderPath = Join-Path $Env:Temp $(New-Guid); New-Item -Type Directory -Path $tempFolderPath | Out-Null

以下是完全限定的临时文件夹路径 ( $tempFolderPath) 的样子:

C:\Users\MassDotNet\AppData\Local\Temp\2ae2dbc4-c709-475b-b762-72108b8ecb9f
于 2019-12-10T16:21:52.047 回答
9

如果您想要保证无竞争和无碰撞的循环解决方案,那么它是:

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
}

根据Michael Kropat 回答中的分析,绝大多数情况下,这只会通过循环一次。很少会通过两次。几乎永远不会通过三遍。

于 2019-02-28T22:26:48.087 回答
3

.NET 已经有[System.IO.Path]::GetTempFileName()很长一段时间了;您可以使用它来生成文件(并捕获名称),然后在删除文件后创建一个具有相同名称的文件夹。

$tempfile = [System.IO.Path]::GetTempFileName();
remove-item $tempfile;
new-item -type directory -path $tempfile;
于 2016-01-01T21:03:23.767 回答
3

这是我的尝试:

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
}
于 2016-01-02T11:13:18.270 回答
2

如果可能的话,我喜欢一个班轮。@alroc .NET 也有[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  
于 2016-01-02T19:49:24.627 回答
0

如果你愿意,你可以非常花哨,GetTempPathA()像这样调用 Windows API 函数:

# 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 ...
  1. https://docs.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-gettemppatha
于 2021-03-25T21:48:40.713 回答
-1

从 Michael Kropat 的回答扩展:https ://stackoverflow.com/a/34559554/8083582

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;
}

这应该消除任何与碰撞有关的问题。

于 2017-07-27T10:07:00.293 回答