是否在PowerShell中创建临时目录?

是否在PowerShell中创建临时目录?,powershell,temporary-directory,Powershell,Temporary Directory,,这很方便。我如何做同样的事情,但不是创建一个文件,而是创建一个目录?是否有新的TemporaryDirectorycmdlet?我认为可以通过使用GUID作为目录名而无需循环: function New-TemporaryDirectory { $parent = [System.IO.Path]::GetTempPath() [string] $name = [System.Guid]::NewGuid() New-Item -ItemType Directory -

,这很方便。我如何做同样的事情,但不是创建一个文件,而是创建一个目录?是否有
新的TemporaryDirectory
cmdlet?

我认为可以通过使用GUID作为目录名而无需循环:

function New-TemporaryDirectory {
    $parent = [System.IO.Path]::GetTempPath()
    [string] $name = [System.Guid]::NewGuid()
    New-Item -ItemType Directory -Path (Join-Path $parent $name)
}
使用GetRandomFileName的原始尝试 这是我的港口:

碰撞可能性分析
GetRandomFileName
返回临时文件夹中已存在的名称的可能性有多大

  • 文件名以
    XXXXXXXX.XXX
    的形式返回,其中X可以是小写字母或数字
  • 这给了我们36^11个组合,以位为单位大约是2^56
  • 调用,我们预计一旦我们得到文件夹中大约2^28个项目(约3.6亿个),就会发生冲突
  • ,因此可以使用
    GetRandomFileName

另一方面,
NewGuid
使得冲突几乎不可能发生。

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

$tempfile = [System.IO.Path]::GetTempFileName();
remove-item $tempfile;
new-item -type directory -path $tempfile;
以下是我的尝试:

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
}

如果可能的话,我喜欢一行@alroc.NET还有
[System.Guid]::NewGuid()


我也喜欢一句俏皮话,我请求在这里投下一票。我所要求的就是你把我自己对这件事模糊的负面感觉用语言表达出来

New-TemporaryFile | %{ rm $_; mkdir $_ }
根据您是什么类型的纯粹主义者,您可以执行
%{mkdir$\ud}
,保留占位符以避免冲突


站在
连接路径$env:TEMP$(新Guid)|%{mkdir$}
上也是合理的。

从Michael Kropat的答案展开:


这将消除任何冲突问题。

如果您希望循环解决方案保证无竞争和无冲突,那么它就是:

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
}

根据中的分析,在绝大多数情况下,这只会通过一次循环。它很少会通过两次。实际上,它永远不会通过三次。

这里是user4317867的一个变体。我在用户的Windows“Temp”文件夹中创建了一个新目录,并使Temp文件夹路径作为变量可用(
$tempFolderPath
):

以下是与一行程序相同的脚本:

$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

如果您愿意,您可以非常花哨地调用Windows API函数
gettempatha()
,如下所示:

# 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 ...

  • 我可能会将
    GetRandomFileName()
    New Item
    放在一个循环中,以便在名称冲突时自动重试。@sodawillow问得好。我错误地认为您需要
    -Force
    来创建不存在的父目录,但我错了,所以我更新了答案。引用MSDN:-Force可以让cmdlet创建一个覆盖现有只读项目的项目。实现因提供商而异。有关更多信息,请参阅关于\u提供程序。即使使用Force参数,cmdlet也无法覆盖安全限制。如果您的临时文件夹中有3.6亿个项目,我认为您的问题比某些PS脚本由于名称冲突而失败的问题更大。在哪里使用了
    $tempfilename
    ?我的错误,我没有复制/粘贴我的最终版本。现在修复了。这段代码面临相同的竞争条件。对我来说,这似乎是一条很好的单行线。除非证明不是这样,否则我会假设存在竞争条件的可能性很小,但对于99%的用例来说,这并不是一个真正的问题。请注意,我已经看到“删除并重新创建”策略在使用慢防病毒软件的系统上失败,正如Raymond Chen在的“异步复制和删除案例”中所暗示的。这是“本机PowerShell”变体:
    New TemporaryFile |%{Remove Item$\uux0;New Item-ItemType Directory-Path$\ux0}
    添加
    -d
    不会避免冲突。(如果您同时在两个不同的脚本中使用相同的方法会怎么样?)但是,您并没有试图避免冲突,是吗?;-)为了澄清这一点,保留占位符可以避免冲突(直到重新实现commandlet),如果它们在实践中存在风险的话。任意确定的
    -d
    是为了避免所谓的“冲突”在结果文件和目录之间。此代码在
    while
    New Item
    命令的结尾之间面临竞争条件。此代码在
    while
    New Item
    命令的结尾之间面临竞争条件,如上所述。这不起作用,如果发生碰撞,它将陷入无限循环中。。。因为$name在循环中没有更新。对,我错了。我刚刚将名称创建移到了循环中。如果由于任何原因失败,它也会抛出一个难看的错误。它还返回两个对象(因为新项返回一个对象)。你的总体方法是合理的,但我在你的帖子中提交了一个编辑,以解决我发现的问题。据我所知,它似乎起了作用。:-)这正是
    Path.GetTempPath
    在内部为您所做的代码。@martin prikryl很好的跟进,您知道如何查看该内部代码吗?+尽管它将正确地使用Unicode版本的API,这与传统的Ansi版本相反。
    $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
    
    C:\Users\MassDotNet\AppData\Local\Temp\2ae2dbc4-c709-475b-b762-72108b8ecb9f
    
    # 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 ...