Help with Test-Path in foreach loop

I am trying to add some logic to my function that will check to see if a folder exists and copies the data. If the folder does not exist, it will create the folder using the $destinationfolder variable. When I run the below code, the script will not add the $destinationfolder directory to the remote computer. Any guidance would be appreciated and thanks for your time.

I verified that my script works if I take out the If Construct.

 

function Copy-RCSSFile {

<#

.SYNOPSIS

Copy files from a given path to a remote computer.

#>

[CmdletBinding()]

param (

[Parameter(Mandatory=$True,

ValueFromPipeline=$True,

ValueFromPipelineByPropertyName=$True)]

[string]$computername,

[Parameter(Mandatory=$True,

ValueFromPipelineByPropertyName=$True)]

[string]$path,

[Parameter(Mandatory=$True,

ValueFromPipelineByPropertyName=$True)]

[string]$destination,

[Parameter(ValueFromPipelineByPropertyName=$True)]

[string]$destinationfolder

) # param

BEGIN {

Setting up DestinationFolder

Write-Verbose"Setting $destinationfolder variable"

$destinationfolder=“C:_Code”

} #BEGIN

PROCESS {

foreach ($computerin$ComputerName) {

Setting up Session to remote computer

Write-Verbose"Connecting to $computer to copy items"

$session=New-PSSession-ComputerName $computer

Write-Verbose"Checking to see if $destinationfolder exists on $computer"

If (-not (Test-Path-LiteralPath $destinationfolder)) {

Try {

Write-Verbose"Creating $destinationfolder on $computer"

New-Item-Path $destinationfolder-ItemType Directory -ErrorAction Stop

}

Catch {

Write-Error-Message “Unable to create directory ‘$destinationfolder’. Error was: $_”-ErrorAction Stop

}

} Else {

Write-Verbose"Directory already exists"

} # If

Write-Verbose"Copying files to $computer"

Copy-Item-Path $path-Destination $destination-ToSession $session

Write-Verbose"Closing $computer session"

Remove-PSSession-Session $session

} # foreach

} #PROCESS

END {

} #END

} #function

Assuming this is a direct copy of your actual script, there are a lot of missing spaces in your code. For example, line 74 should be
[pre]$session=New-PSSession -ComputerName $computer[/pre]
“New-PSSession-ComputerName” will not work.

[pre]New-Item-Path $destinationfolder-ItemType Directory -ErrorAction Stop[/pre]

The main thing I noticed, there is a missing space between $destinationfolder and -ItemType on line 87.

[pre]New-Item-Path $destinationfolder -ItemType Directory -ErrorAction Stop[/pre]

Ok, so I went through your code and cleaned it up. I haven’t changed any of the functionality, just reformatted for readability and added or removed spaces as needed.
<script src=“https://gist.github.com/grokk-it/c2a700ffdcb141834111735dca01021c.js”></script>
I think parts of it are still broken. For instance, you have a $destinationfolder parameter but in the BEGIN section you set $destinationfolder (line 46), which would overwrite any parameter input. You should probably check to see if $destinationfolder has anything set in this section. Also, the value it’s set to looks odd - should it be C:$_Code instead?

Also, I want to recommend using the PowerShell ISE to help with your code formatting.

Sorry Everyone, the paste did not format everything correctly. I will reformat the script

 

function Copy-RCSSFile {
<#
.SYNOPSIS
Copy files from a given path to a remote computer.
#>
[CmdletBinding()]
param (
[Parameter(Mandatory=$True,
ValueFromPipeline=$True,
ValueFromPipelineByPropertyName=$True)]
[string]$computername,
[Parameter(Mandatory=$True,
ValueFromPipelineByPropertyName=$True)]
[string]$path,
[Parameter(Mandatory=$True,
ValueFromPipelineByPropertyName=$True)]
[string]$destination,
[Parameter(ValueFromPipelineByPropertyName=$True)]
[string]$destinationfolder
) # param
BEGIN {
# Setting up DestinationFolder
Write-Verbose "Setting $destinationfolder variable"
$destinationfolder= "C:\_Code"
} #BEGIN
PROCESS {
foreach ($computer in $ComputerName) {
# Setting up Session to remote computer
Write-Verbose "Connecting to $computer to copy items"
$session= New-PSSession -ComputerName $computer
Write-Verbose "Checking to see if $destinationfolder exists on $computer"
If (-not (Test-Path -LiteralPath $destinationfolder)) {
Try {
Write-Verbose "Creating $destinationfolder on $computer"
New-Item -Path $destinationfolder -ItemType Directory -ErrorAction Stop
}
Catch {
Write-Error -Message "Unable to create directory '$destinationfolder'. Error was: $_" -ErrorAction Stop
}
} Else {
Write-Verbose "Directory already exists"
} # If
Write-Verbose "Copying files to $computer"
Copy-Item -Path $path -Destination $destination -ToSession $session
Write-Verbose "Closing $computer session"
Remove-PSSession -Session $session
} # foreach
} #PROCESS
END {
} #END
} #function

I want the destination folder to be C:_Code on a given machine. We like to use “_” in folder names when it deals with IT. Additionally, I use Visual Studio Code with the powershell extension.

Action:

When I tested the script, I statically setup $destinationfolder variable to see if will work. I verified I got the “Directory already exists” prompt when I run it on a machine that has the folder. However, when I run the function/script on a machine that does not have the given folder, it does not create the $destinationfolder.

I am going to continue to test the script to see where the issue lies.

Are you getting “Creating C:_Code on $computer” and/or "Unable to create directory … " error?

Write to the root drive generally requires Admin privileges and may throw an Access is denied error.

Oh, yes the New-Item line is wrong. Based on your parameters, it should look like this:
[pre]New-Item -Path $destination -Name $destinationfolder -ItemType Directory -ErrorAction Stop[/pre]
-Path is the path to the parent folder that will contain the directory you are creating
-Name is the name of the new folder you are creating (it is required)
See Example 2 in the documentation.

You have other problems though. For instance, your comment block at the top isn’t working because you have a space between the “<” and the “#”.

Also, try using Set-PSDebug -Trace 1 to help with debugging.

I am receiving the following information when running -Verbose parameter.

 

VERBOSE: Setting variable
VERBOSE: Connecting to Dev-PShell to copy items
VERBOSE: Checking to see if C:_Code exists on Dev-PShell
VERBOSE: Directory already exists
VERBOSE: Copying files to Dev-PShell
Copy-Item : Cannot find path ‘C:_Code\setup.exe’ because it does not exist.
At C:\ProgramData_Install\Copy-RCSSFile.ps1:54 char:13

  • Copy-Item -Path $path -Destination $destination -ToSessio …
  • CategoryInfo : WriteError: (C:_Code\setup.exe:String) [Copy-Item], ArgumentException
  • FullyQualifiedErrorId : RemotePathNotFound,Microsoft.PowerShell.Commands.CopyItemCommand

VERBOSE: Closing Dev-PShell session

 

The Folder C:_Code is not present.

 

Is there a way to verify the folder without using the “-not” syntax in the If construct?

Chance, I think you are answering the issue. I believe it is a permission error. I am going to move the folder path and see what I get.

Upon further testing, I found that the If Construct was looking at the original computer for the destinationfolder. I will need to continue to research.

Could try using the admin share to test the path. For example:

Test-Path -Path “\$computer\C$$destinationfolder”

Just keep in mind, you might need a PSCredential to automate the process.

Looking at part of the script:

foreach ($computer in $ComputerName) {
# Setting up Session to remote computer
Write-Verbose "Connecting to $computer to copy items"
$session= New-PSSession -ComputerName $computer
Write-Verbose "Checking to see if $destinationfolder exists on $computer"
If  (-not (Test-Path -LiteralPath $destinationfolder)) {
Try {
Write-Verbose "Creating $destinationfolder on $computer"
New-Item -Path $destinationfolder -ItemType Directory -ErrorAction Stop
}
Catch {
Write-Error -Message "Unable to create directory '$destinationfolder'. Error was: $_" -ErrorAction Stop
}
} Else {
Write-Verbose "Directory already exists"
}

I see you’ve created a session, but I don’t see where its being used for the test.

invoke-command -session $session -scriptblock {
 If  (-not (Test-Path -LiteralPath $using:destinationfolder)) {
 write-host not here
 } else {
 write-host we got it}
 }

That will use the session to test on the remote server. the $using:destinationfolder passes the local variable into the remote scriptblock.

 

All,

 

I have fixed the script using all your guidance. It is not pretty but here is the script below (I am going to try to import from GitHub):

I used the $using: tip to pass the variable into my script to check if the path is found. I added the variable in my Try block to assist with Copy-Item creating the path. Thanks for all your help everyone!

https://github.com/hoybyte/PowershellScripts/blob/master/Copy-RCSSFile.ps1