Een betere manier om te controleren of er een pad bestaat of niet in PowerShell

Oorspronkelijke reden(en) zijn niet opgelost


Antwoord 1, autoriteit 100%

Als je alleen een alternatief wilt voor de cmdlet-syntaxis, specifiek voor bestanden, gebruik dan de File.Exists().NET-methode:

if(![System.IO.File]::Exists($path)){
    # file with path $path doesn't exist
}

Als u aan de andere kant een genegeerde alias voor algemeen gebruik wilt voor Test-Path, moet u dit als volgt doen:

# Gather command meta data from the original Cmdlet (in this case, Test-Path)
$TestPathCmd = Get-Command Test-Path
$TestPathCmdMetaData = New-Object System.Management.Automation.CommandMetadata $TestPathCmd
# Use the static ProxyCommand.GetParamBlock method to copy 
# Test-Path's param block and CmdletBinding attribute
$Binding = [System.Management.Automation.ProxyCommand]::GetCmdletBindingAttribute($TestPathCmdMetaData)
$Params  = [System.Management.Automation.ProxyCommand]::GetParamBlock($TestPathCmdMetaData)
# Create wrapper for the command that proxies the parameters to Test-Path 
# using @PSBoundParameters, and negates any output with -not
$WrappedCommand = { 
    try { -not (Test-Path @PSBoundParameters) } catch { throw $_ }
}
# define your new function using the details above
$Function:notexists = '{0}param({1}) {2}' -f $Binding,$Params,$WrappedCommand

notexistszullen zich nu exactgedragen als Test-Path, maar retourneren altijd het tegenovergestelde resultaat:

PS C:\> Test-Path -Path "C:\Windows"
True
PS C:\> notexists -Path "C:\Windows"
False
PS C:\> notexists "C:\Windows" # positional parameter binding exactly like Test-Path
False

Zoals je jezelf al hebt laten zien, is het tegenovergestelde vrij eenvoudig, alias existsnaar Test-Path:

PS C:\> New-Alias exists Test-Path
PS C:\> exists -Path "C:\Windows"
True

Antwoord 2, autoriteit 33%

De alias-oplossing die je hebt gepost is slim, maar ik zou tegen het gebruik ervan in scripts pleiten, om dezelfde reden dat ik er niet van houd om aliassen in scripts te gebruiken; het heeft de neiging de leesbaarheid te schaden.

Als dit iets is dat je aan je profiel wilt toevoegen, zodat je snelle commando’s kunt typen of het als shell kunt gebruiken, dan zou dat logisch zijn.

U kunt in plaats daarvan piping overwegen:

if ($path | Test-Path) { ... }
if (-not ($path | Test-Path)) { ... }
if (!($path | Test-Path)) { ... }

Als alternatief kunt u voor de negatieve benadering, indien van toepassing op uw code, er een positieve controle van maken en vervolgens elsegebruiken voor de negatieve:

if (Test-Path $path) {
    throw "File already exists."
} else {
   # The thing you really wanted to do.
}

Antwoord 3, autoriteit 7%

Voeg de volgende aliassen toe. Ik denk dat deze standaard beschikbaar moeten zijn in PowerShell:

function not-exist { -not (Test-Path $args) }
Set-Alias !exist not-exist -Option "Constant, AllScope"
Set-Alias exist Test-Path -Option "Constant, AllScope"

Daarmee veranderen de voorwaardelijke uitspraken in:

if (exist $path) { ... }

en

if (not-exist $path) { ... }
if (!exist $path) { ... }

Antwoord 4, autoriteit 2%

Een andere optie is om IO.FileInfote gebruiken, dat je zoveel bestandsinformatie geeft dat het het leven gemakkelijker maakt door alleen dit type te gebruiken:

PS > mkdir C:\Temp
PS > dir C:\Temp\
PS > [IO.FileInfo] $foo = 'C:\Temp\foo.txt'
PS > $foo.Exists
False
PS > New-TemporaryFile | Move-Item -Destination C:\Temp\foo.txt
PS > $foo.Refresh()
PS > $foo.Exists
True
PS > $foo | Select-Object *
Mode              : -a----
VersionInfo       : File:             C:\Temp\foo.txt
                    InternalName:
                    OriginalFilename:
                    FileVersion:
                    FileDescription:
                    Product:
                    ProductVersion:
                    Debug:            False
                    Patched:          False
                    PreRelease:       False
                    PrivateBuild:     False
                    SpecialBuild:     False
                    Language:
BaseName          : foo
Target            : {}
LinkType          :
Length            : 0
DirectoryName     : C:\Temp
Directory         : C:\Temp
IsReadOnly        : False
FullName          : C:\Temp\foo.txt
Extension         : .txt
Name              : foo.txt
Exists            : True
CreationTime      : 2/27/2019 8:57:33 AM
CreationTimeUtc   : 2/27/2019 1:57:33 PM
LastAccessTime    : 2/27/2019 8:57:33 AM
LastAccessTimeUtc : 2/27/2019 1:57:33 PM
LastWriteTime     : 2/27/2019 8:57:33 AM
LastWriteTimeUtc  : 2/27/2019 1:57:33 PM
Attributes        : Archive

Meer details op mijn blog.


Antwoord 5, autoriteit 2%

Gebruik deze om te controleren of er een pad naar een map bestaat:

$pathToDirectory = "c:\program files\blahblah\"
if (![System.IO.Directory]::Exists($pathToDirectory))
{
 mkdir $path1
}

Om te controleren of er een pad naar een bestand bestaat, gebruikt u wat @Mathiasheeft voorgesteld:

[System.IO.File]::Exists($pathToAFile)

Antwoord 6, autoriteit 2%

Dit is mijn nieuwe powershell-manier om dit te doen

if ((Test-Path ".\Desktop\checkfile.txt") -eq $true) {
    Write-Host "Yay"
} 
else {
    Write-Host "Damn it"
}

Antwoord 7

if (Test-Path C:\DockerVol\SelfCertSSL) {
    write-host "Folder already exists."
} else {
   New-Item -Path "C:\DockerVol\" -Name "SelfCertSSL" -ItemType "directory"
}

Antwoord 8

Na het uitstekende antwoord van @Mathias R. Jessen te hebben bekeken, kwam het bij me op dat je geen twee nieuwe functies hoeft te creëren. In plaats daarvan kunt u een wrapper maken rond de native functie Test-Pathmet dezelfde naam die een schakeloptie -Nottoevoegt:

$TestPathCmd = Get-Command Test-Path
$TestPathCmdMetaData = New-Object System.Management.Automation.CommandMetadata $TestPathCmd
$Binding = [System.Management.Automation.ProxyCommand]::GetCmdletBindingAttribute($TestPathCmdMetaData)
$Params  = [System.Management.Automation.ProxyCommand]::GetParamBlock($TestPathCmdMetaData)
$Params += ', [Switch]${Not}'
$WrappedCommand = {
    $PSBoundParameters.Remove('Not') | Out-Null
    [Bool]($Not.ToBool() -bxor (Microsoft.PowerShell.Management\Test-Path @PSBoundParameters))
}
${Function:Test-Path} = '{0} Param({1}) {2}' -f $Binding,$Params,$WrappedCommand

Bijvoorbeeld:

Test-Path -Path 'C:\Temp'      # True
Test-Path -Path 'C:\Temp' -Not # False
Test-Path -Path 'C:\Txmp'      # False
Test-Path -Path 'C:\Txmp' -Not # True

Dit heeft een aantal voordelen:

  1. Vertrouwde syntaxis: wanneer u de aangepaste schakelaar niet gebruikt, is de syntaxis identiek aan de oorspronkelijke opdracht, en als u dat wel doet, is het vrij intuïtief wat er gebeurt, wat minder cognitieve belasting voor de gebruiker betekent en meer compatibiliteit bij het delen.
  2. Omdat de wrapper de native functie onder de motorkap aanroept, werkt het overal waar de native functie werkt, bijvoorbeeld:
    Test-Path -Path 'HKLM:\SOFTWARE'      # True
    Test-Path -Path 'HKLM:\SOFTWARE' -Not # False
    Test-Path -Path 'HKLM:\SXFTWARE'      # False
    Test-Path -Path 'HKLM:\SXFTWARE' -Not # True
    

Other episodes