J'écris un fichier batch qui exécute un script Powershell qui à un moment donné boucle des éléments avec des chemins UNC comme attributs et utilise Get-ChildItem
sur ces chemins. Dans une version minimale, c'est ce qui se passe dans mes scripts:
Master.bat
powershell -ExecutionPolicy ByPass -File "Slave.ps1"
Slave.ps1
$foo = @{Name = "Foo"}
$foo.Path = "\\remote-server\foothing"
$bar = @{Name = "Bar"}
$bar.Path = "\\remote-server\barthing"
@( $foo, $bar ) | ForEach-Object {
$item = Get-ChildItem $_.Path
# Do things with item
}
Le problème que je rencontre est que lorsque j'exécute Master.bat , il échoue à Get-ChildItem
avec une erreur du type
get-childitem : Cannot find path '\\remote-server\foothing' because it does not exist.
Cependant, cela semble fonctionner parfaitement si j'exécute le fichier Slave.ps1 directement à l'aide de Powershell. Pourquoi cela peut-il se produire uniquement lorsque le fichier Master.bat est exécuté?
Ce que j'ai essayé
FileSystem::
avec les fournisseurs http://powershell.org/wp/2014/02/20/powershell-gotcha-unc-paths-and-providers/-literalPath
paramètre au lieu du simple -path
paramètre pour Get-ChildItem
Get-ChildItem \\remote-server\foothing
dans PowerShell et réussissant à vérifier la connexion au serveur distantJ'ai rencontré ce problème lors de l'exécution de scripts faisant référence à des chemins UNC - mais l'erreur ne se produit que lorsque la racine du script est définie sur un emplacement autre que le système de fichiers. par exemple. PS SQLSEVER \
Donc, ce qui suit échoue avec la même erreur:
cd env:
$foo = @{Name = "Foo"}
$foo.Path = "\\remote-server\foothing"
$bar = @{Name = "Bar"}
$bar.Path = "\\remote-server\barthing"
@( $foo, $bar ) | ForEach-Object {
$item = Get-ChildItem $_.Path
# Do things with item
Write-Host $item
}
Donc, ma résolution était de m'assurer que l'invite PS était retournée à un emplacement du système de fichiers avant d'exécuter ce code. par exemple.
cd env:
$foo = @{Name = "Foo"}
$foo.Path = "\\remote-server\foothing"
$bar = @{Name = "Bar"}
$bar.Path = "\\remote-server\barthing"
cd c: #THIS IS THE CRITICAL LINE
@( $foo, $bar ) | ForEach-Object {
$item = Get-ChildItem $_.Path
# Do things with item
Write-Host $item
}
J'espère que cela aide - je serais très heureux de la prime car c'est ma première réponse sur le débordement de pile. P.S. J'ai oublié d'ajouter - la racine d'invite de commande PS peut être définie par des modules chargés automatiquement dans la configuration de votre machine. Je vérifierais avec Get-Location pour voir si vous exécutez réellement à partir d'un emplacement non FileSystem.
réponse de Rory fournit une solution de contournement efficace, mais il existe une solution qui ne nécessite pas de changer l'emplacement actuel en un emplacement de fournisseur FileSystem en premier :
Préfixez vos chemins UNC avec FileSystem::
pour vous assurer qu'ils sont reconnus correctement, quel que soit l'emplacement actuel:
$foo = @{Name = "Foo"}
$foo.Path = "FileSystem::\\remote-server\foothing"
$bar = @{Name = "Bar"}
$bar.Path = "FileSystem::\\remote-server\barthing"
Alternativement, voici un Tweak à la réponse de Rory pour éviter de changer la session d'emplacement actuelle de manière globale (pour conserver l'emplacement actuel), en utilisant Push-Location
et Pop-Location
:
try {
# Switch to the *filesystem provider's* current location, whatever it is.
Push-Location (Get-Location -PSProvider FileSystem)
# Process the paths.
@( $foo, $bar ) | ForEach-Object {
$item = Get-ChildItem $_.Path
# Do things with item
}
} finally {
# Restore the previous location.
Pop-Location
}
Cet excellent article de blog explique le problème sous-jacent (emphase ajoutée):
PowerShell ne reconnaît pas les [chemins UNC] comme "enracinés" car ils ne sont pas sur un PSDrive; en tant que tel, , quel que soit le fournisseur associé à l'emplacement actuel de PowerShell, il tentera de les gérer .
Ajout du préfixe FileSystem::
identifie sans ambiguïté le chemin comme étant un chemin de fournisseur FileSystem, quel que soit le fournisseur sous-jacent à l'emplacement actuel.
J'ai lu ailleurs sur le Push-Location
et Pop-Location
commandes pour contrer ce genre de problème - J'ai atterri sur votre question en testant manuellement, étape par étape, une nouvelle routine où le script a Push/pop, mais j'ai oublié de les faire sur ma fenêtre PS. Après avoir vérifié la réponse de @ Rory, j'ai remarqué que j'étais sur PS SQLServer:\au lieu de PS C:\Prompt.
Donc, une façon de l'utiliser sur votre script "esclave" serait:
$foo = @{Name = "Foo"}
$foo.Path = "\\remote-server\foothing"
$bar = @{Name = "Bar"}
$bar.Path = "\\remote-server\barthing"
@( $foo, $bar ) | ForEach-Object {
$item = Get-ChildItem $_.Path
Push-Location
# Do things with item
Pop-Location
}
Pensé à ajouter le Push/Pop avant et après le # Do things
car il semble que ce sont ces choses qui changent l'emplacement.