$from = "\\something\1 XLS\2010_04_22\*"
$to = "c:\out\1 XLS\2010_04_22\"
copy-item $from $to -Recurse
Cela fonctionne si c:\out\1 XLS\2010_04_22\existe. Est-il possible avec une seule commande de créer "c:\out\1 XLS\2010_04_22 \" s'il n'existe pas.
Oui, ajoutez le paramètre -Force
.
copy-item $from $to -Recurse -Force
Dans PowerShell 2.0, il n’est toujours pas possible d’obtenir la cmdlet Copy-Item pour créer le dossier de destination, vous aurez besoin d’un code comme celui-ci:
$destinationFolder = "C:\My Stuff\Subdir"
if (!(Test-Path -path $destinationFolder)) {New-Item $destinationFolder -Type Directory}
Copy-Item "\\server1\Upgrade.exe" -Destination $destinationFolder
Si vous utilisez -Recurse dans l'élément de copie, tous les sous-dossiers de la structure source de la destination seront créés, mais le dossier de destination réel ne sera pas créé, même avec -Force.
Dans PowerShell 3 et les versions ultérieures, j'utilise l'élément Copier avec Nouvel élément.
copy-item -Path $file -Destination (new-item -type directory -force ("C:\Folder\sub\sub\" + $newSub)) -force -ea 0
Je n'ai pas essayé dans la version 2.
function Copy-File ([System.String] $sourceFile, [System.String] $destinationFile, [Switch] $overWrite) {
if ($sourceFile -notlike "filesystem::*") {
$sourceFile = "filesystem::$sourceFile"
}
if ($destinationFile -notlike "filesystem::*") {
$destinationFile = "filesystem::$destinationFile"
}
$destinationFolder = $destinationFile.Replace($destinationFile.Split("\")[-1],"")
if (!(Test-Path -path $destinationFolder)) {
New-Item $destinationFolder -Type Directory
}
try {
Copy-Item -Path $sourceFile -Destination $destinationFile -Recurse -Force
Return $true
} catch [System.IO.IOException] {
# If overwrite enabled, then delete the item from the destination, and try again:
if ($overWrite) {
try {
Remove-Item -Path $destinationFile -Recurse -Force
Copy-Item -Path $sourceFile -Destination $destinationFile -Recurse -Force
Return $true
} catch {
Write-Error -Message "[Copy-File] Overwrite error occurred!`n$_" -ErrorAction SilentlyContinue
#$PSCmdlet.WriteError($Global:Error[0])
Return $false
}
} else {
Write-Error -Message "[Copy-File] File already exists!" -ErrorAction SilentlyContinue
#$PSCmdlet.WriteError($Global:Error[0])
Return $false
}
} catch {
Write-Error -Message "[Copy-File] File move failed!`n$_" -ErrorAction SilentlyContinue
#$PSCmdlet.WriteError($Global:Error[0])
Return $false
}
}
Mon préféré est d'utiliser la classe .Net [IO.DirectoryInfo], qui gère une partie de la logique. En fait, je l’utilise pour beaucoup de défis de script similaires. Il a une méthode .Create () qui crée des répertoires qui n'existent pas, sans erreurs s'ils existent.
Comme il s’agit toujours d’un problème en deux étapes, j’utilise l’alias foreach pour que cela reste simple. Pour des fichiers uniques:
[IO.DirectoryInfo]$to |% {$_.create(); cp $from $_}
Pour ce qui est de la correspondance de plusieurs fichiers/répertoires, j'utiliserais RoboCopy sur xcopy. Supprimez le "*" de votre et utilisez simplement:
RoboCopy.exe $from $to *
Vous pouvez toujours ajouter le/r (Recurse),/e (Recurse, y compris un vide), et il existe 50 autres commutateurs utiles.
Edit: En regardant en arrière, il est concis, mais pas très lisible si vous n’utilisez pas souvent le code. Habituellement, je l'ai divisé en deux, comme ceci:
([IO.DirectoryInfo]$to).Create()
cp $from $to
De plus, DirectoryInfo est le type de la propriété Parent de FileInfo. Par conséquent, si votre $ à est un fichier, vous pouvez les utiliser ensemble:
([IO.FileInfo]$to).Parent.Create()
cp $from $to
Voici un exemple qui a fonctionné pour moi. J'avais une liste d'environ 500 fichiers spécifiques dans un fichier texte, contenu dans environ 100 dossiers différents, que j'étais supposé copier sur un emplacement de sauvegarde au cas où ces fichiers seraient nécessaires ultérieurement. Le fichier texte contenait le chemin complet et le nom du fichier, un par ligne. Dans mon cas, je voulais enlever la lettre de lecteur et le nom du premier sous-dossier de chaque nom de fichier. Je voulais copier tous ces fichiers dans une structure de dossiers similaire sous un autre dossier de destination racine que j'ai spécifié. J'espère que les autres utilisateurs trouvent cela utile.
# Copy list of files (full path + file name) in a txt file to a new destination, creating folder structure for each file before copy
$rootDestFolder = "F:\DestinationFolderName"
$sourceFiles = Get-Content C:\temp\filelist.txt
foreach($sourceFile in $sourceFiles){
$filesplit = $sourceFile.split("\")
$splitcount = $filesplit.count
# This example strips the drive letter & first folder ( ex: E:\Subfolder\ ) but appends the rest of the path to the rootDestFolder
$destFile = $rootDestFolder + "\" + $($($sourceFile.split("\")[2..$splitcount]) -join "\")
# Output List of source and dest
Write-Host ""
Write-Host "===$sourceFile===" -ForegroundColor Green
Write-Host "+++$destFile+++"
# Create path and file, if they do not already exist
$destPath = Split-Path $destFile
If(!(Test-Path $destPath)) { New-Item $destPath -Type Directory }
If(!(Test-Path $destFile)) { Copy-Item $sourceFile $destFile }
}
$filelist | % {
$file = $_
mkdir -force (Split-Path $dest) | Out-Null
cp $file $dest
}
J'ai trébuché ici deux fois, et cette dernière fois était une situation unique et même si j'ai abandonné l'utilisation de copy-item
, je voulais publier la solution que j'ai utilisée.
Avait une liste de rien, mais les fichiers avec le chemin complet et dans la majorité des cas, les fichiers n'ont pas d'extensions. l'option -Recurse -Force
ne fonctionnant pas pour moi, j'ai donc abandonné la fonction copy-item
et je suis tombé à quelque chose comme ci-dessous, à l'aide de xcopy, car je souhaitais tout de même conserver une couche. Au départ, j’étais à égalité avec Robocopy, mais cette dernière est apparemment à la recherche d’une extension de fichier et, comme beaucoup d’entre elles n’ont pas d’extension, elle le considère comme un répertoire.
$filelist = @("C:\Somepath\test\location\here\file","C:\Somepath\test\location\here2\file2")
$filelist | % { echo f | xcopy $_ $($_.Replace("somepath", "somepath_NEW")) }
J'espère que ça aide quelqu'un.