2

This seems like it should be a trivial thing.

I am using Powershell v5.1 and I am trying to build a UNC path from 2 strings that represent a server and a share. Given that $Server hold "Distribution" and $Share holds "Publish"...

 $Path = "\\" + $Server + "\" + $Share

The output I am getting for $Path is..

\\Distribution Publish\

I tried changing it to...

$Path = "//" + $Server + "/" + $Share

...as a test thinking the special character "\" was causing a problem, but then I still get the odd sequence where there is a space between server and share and the 2nd slash is at the end.

//Distribution Publish/

What am I missing?

mklement0
  • 382,024
  • 64
  • 607
  • 775
EiEiGuy
  • 1,447
  • 5
  • 18
  • 32
  • 4
    Are you sure `$server` and `$share` contain what you think, and they're not in fact eg `$server == "Distribution Publish"` and `$share == ""`? What you have [should be fine](https://i.stack.imgur.com/Oi6lk.png). – James Thorpe Jul 27 '17 at 12:49
  • 2
    Can't reproduce in PowerShell 5 and it would indeed be very odd. Check `$Server.Length` and `$Share.Length` to see if they contain any interesting invisible characters that might influence the result (like RTL markers). – Jeroen Mostert Jul 27 '17 at 12:52
  • 1
    As substitution functions within double quotes, `$Path = "\\$Server\$Share"` will do what you want. – henrycarteruk Jul 27 '17 at 13:06
  • @JamesC.: While that is true and is generally a more concise alternative, it is equivalent to what the OP tried and therefore doesn't explain the symptom. – mklement0 Jul 27 '17 at 13:32

2 Answers2

4

As mentioned in the comments, your symptoms cannot be explained if your $Server and $Share variables truly contain just Distribution and Publish, respectively, with no hidden control characters.

Here's a contrived example of variable values that do produce your symptom:

> $Server = 'Distribution', 'Publish'; $Share = "`r"; "\\" + $Server + "\" + $Share
\\Distribution Publish\

As James C. points out, a more concise alternative for building the string is: "\\$Server\$Share".
As TheIncorrigible1 points out, it is better to build paths using Join-Path.

  • 'Distribution', 'Publish' is an array of strings, whose elements PowerShell concatenates with a space (by default) when converting it to a string, which in this case results in Distribution Publish.

  • "`r" creates control character CR (0xD), which, when printing to the console, resets the cursor position to the first column and prints the remainder of the string there (which in this case is empty).
    Note, however, that the CR is still a part of the string, albeit an invisible one.
    If you want an easy way to inspect a given string for hidden control characters, see this answer of mine.


Update:

The OP reports that it turned out to be how the $Server and $Share variables were bound via parameters, through mistaken use of (C#) method-invocation syntax:

# Correct invocation: $Server binds to 1st parameter, $Share to 2nd.
./script $Server $Share

# INCORRECT: Binds *both* values to the *first* parameter, as an *array*
#            and assigns nothing to the second.
#            In PowerShell, "," constructs an array.
./script($Server, $Share) 

The tricky thing is that ./script($Server, $Share) happens to be valid PowerShell syntax too, only with different semantics: $Server, $Share constructs a 2-element array whose elements are the values of $Server and $Share, respectively.

To avoid this pitfall, PowerShell offers strict-mode setting Set-StrictMode -Version 2, which reports an error when method-style invocation is attempted. Note, however, that this setting invariably enables other checks as well, notably causing an error when referencing non-existent properties - see Get-Help Set-StrictMode.

mklement0
  • 382,024
  • 64
  • 607
  • 775
  • @EiEiGuy: Glad to hear it. I see; yes, passing arguments C#-style is a common pitfall - please see my update. – mklement0 Jul 27 '17 at 14:50
2

Avoid string addition like you're doing when working with paths; there are cmdlets that handle that.

$Server = '\\This.server.name'
$File = 'something.exe'
$UNC = Join-Path $Server $File

Additionally, do string validation if you're running into weird errors.

If (!$Server) { "Stuff"; Return } # Checks empty string
If (!$File)   { "Stuff"; Return }
If (!(Test-Path $UNC)) { "Stuff"; Return } # error checking for the file
Maximilian Burszley
  • 18,243
  • 4
  • 34
  • 63
  • What I am doing is accepting a server name and a share name as arguments to my file copying script and trying to validate the destination UNC up front. I am stripping any user provided "\" or "/" characters and then building the correct \\server\share path before I call Test-Path. I will give you a +1 for Join-Path though – EiEiGuy Jul 27 '17 at 14:41
  • Yes, `Join-Path` is good advice. @TheIncorrigible1: your UNC path is missing a _share_ component, however. Also, I suggest not using `Return` for error handling. – mklement0 Jul 27 '17 at 14:53
  • Yes, ideally you'd be using `[CmdletBinding()]` and `$PSCmdlet.ThrowTerminatingError()`, but this was a quick example. The share can be specified in the `$Server` variable or more aptly renamed to `$Share` – Maximilian Burszley Jul 27 '17 at 14:56