Author Posts

May 13, 2014 at 6:48 am

Hello experts,

I am new to powershell and I am writing a powershell script to copy certain files from temp location to target directories, this is where I am right now:

$sourcedirectory = "C:\temp\Source"
$targetdirectory = "C:\Users\Dest"
$backupdirectory = "C:\Users\Dest\"
#get-location
#cd $sourcedirectory
#get-location
#Get-ChildItem -recurse | where {$_.PsIsContainer} | Select-Object Name
#dir -r | % { if ($_.PsIsContainer) {$_.Name} }
#Resolve-Path -relative

if (!(Test-Path -path $targetdirectory)) {New-Item $targetdirectory -Type Directory}
#Take back up of existing file
$backup_directory = New-Item -Path "$backupdirectory\backup_$(Get-Date -Format yyyyMMdd)" -Force -ItemType Directory
Write-Host Copying contents from $targetdirectory to $backup_directory
Copy-Item -Path $targetdirectory -recurse -Destination "$($backup_directory.Fullname)" -Force

#Copy files from source to destination
#Write-Host Following files needs to be copied:

$absolutePath = Get-ChildItem -Path $sourcedirectory -recurse
foreach ($item in $absolutePath)
{
Write-Host Copying $item.FullName to $targetdirectory
Copy-Item -Path $sourcedirectory/* -recurse -force -Destination $targetdirectory
}

My directory structure at source looks like below:
Source\
+-Client\
+-bin\
+-ext\
+-ext64\
+-lib\
+-Patches\
+-Server\
+-ext\
+-ext64\
+-Patches\

On Dest, same folder structure is available as well.

Using powershell command i just want the output like below:
\Source\Client\bin
\Source\Client\ext
\Source\Client\patches....

\Source\Server\ext
\Source\Server\ext24
\Source\Server\patches
The Get-ChildItems commands I have tried so far gives me the absolute path, i want output to be listed in above manner i.e remove C:\temp from the output. I will use this in my for loop for a proper message as stdout here:

Write-Host Copying $item.FullName to $targetdirectory\

Also, please let me know if script looks ok altogether or not.

May 13, 2014 at 10:06 am

First off think about using Write-verbose rather than Write-Host. You probably need quotes round the message you are writing.

There is no straightforward way to remove the c:\temp part of the path

You can remove the c: using split-path with the -NoQualifier parameter which outputs a string. You could use something like this

get-childitem C:\Temp -Filter *.xml | select fullname | Split-Path -NoQualifier | foreach{$_.Replace("\Temp","")}

but its very ugly

May 13, 2014 at 10:48 am

You could do something like this to trim "c:\temp" from the beginning of the strings:

function Remove-LeadingString
{
    [CmdletBinding()]
    param (
        [Parameter(Mandatory = $true, ValueFromPipeline = $true)]
        [AllowEmptyString()]
        [string[]]
        $String,

        [Parameter(Mandatory = $true)]
        [string]
        $LeadingString
    )

    process
    {
        foreach ($s in $String)
        {
            if ($s.StartsWith($LeadingString, $true, [System.Globalization.CultureInfo]::InvariantCulture))
            {
                $s.Substring($LeadingString.Length)
            }
            else
            {
                $s
            }
        }
    }
}

$paths = @(
    'C:\Temp\Testing 123'
    '\Something\Else'
    'c:\temp\whatever\subfolder'
)

$paths | Remove-LeadingString -LeadingString 'C:\temp'

If you don't mind regular expressions and don't need the pipeline support, you don't even need a function. You can just use the -replace operator:

$paths = @(
    'C:\Temp\Testing 123'
    '\Something\Else'
    'c:\temp\whatever\subfolder'
)

$paths -replace '^c:\\temp'

May 14, 2014 at 3:34 am

In addition to what has already been suggested, maybe you could benefit from something like this:

$pathParts = $path.Split([system.io.path]::DirectorySeparatorChar)

That would put the different parts of your sourcepath in the array $pathParts. Lets say you have four parts to your path, and you don't want the first bit. Then you can simply use this as follows (the array is zero based):

Copy-Item $sourcefile [System.IO.Path]::Combine( $pathParts[1], $pathParts[2], $pathParts[3])

This example is taking advantage of the .NET Framework System.Path object. It is a lot safer to add paths together using Path.Combine!

May 14, 2014 at 4:18 am

You could also use Join-Path to create the destination