PS C:\Users\user> Split-Path "http://localhost:9200/index" -Parent
http:\\localhost:9200
In above example, I am trying to extract everything before the /index. I thought Split-Path would do the job but it changes the forward slashes in http:// to back slashes.
"http://localhost:9200/index" -replace ([Uri]"http://localhost:9200/index").AbsolutePath
I've worked out the above alternative which works but Split-Path just seems cleaner. Just wondering why it does that with the forward slashes?
CodePudding user response:
Use the [uri]
type accelerator. Like so,
$u = [uri]"http://localhost:9200/index"
$u.LocalPath # Get the local path property
/index
Since accelerator creates an Uri obect, it works with more complex urls too. E.g.
$u = [uri]"http://localhost:9200/index/data.htm?foo=bar&qaz=zof"
$u # Print members, some omitted for brevity
AbsolutePath : /index/data.htm
AbsoluteUri : http://localhost:9200/index/data.htm?foo=bar&qaz=zof
LocalPath : /index/data.htm
Authority : localhost:9200
...
PathAndQuery : /index/data.htm?foo=bar&qaz=zof
Segments : {/, index/, data.htm}
IsUnc : False
Host : localhost
Port : 9200
Query : ?foo=bar&qaz=zof
...
OriginalString : http://localhost:9200/index/data.htm?foo=bar&qaz=zof
...
To get just the protocol and authority part, either search and replace, or join properties. Like so,
# -replace
$u.OriginalString -replace [regex]::escape($u.PathAndQuery), ''
http://localhost:9200
# build string
"{0}://{1}:{2}" -f $u.scheme, $u.host, $u.port
http://localhost:9200
CodePudding user response:
It seems like that behavior is platform dependent, I ran your example with Split-path on both Windows and macOS and on windows you will get a backslash, while on macOS you will get a regular slash....
CodePudding user response:
Split-Path returns a specified part of a (file) path and in Windows the directories are separated using a backslash. If you run the same command on Linux, you will probably get the desired output.
The best way would probably be the solution from Mathias (parse the URI and format the string). Another workaround with the Split-Path
cmdlet would be to replace all backslashes with forward slashes:
(Split-Path "http://localhost:9200/index" -Parent) -replace '\\', '/'
CodePudding user response:
Split-Path
works with provider paths only. Instead, use the .NET class Uri
that is specifically made for parsing URIs.
Using the method Uri.GetLeftPart()
, a partial URI can be extracted from the URI. This is much easier than building it "manually" by concatenating the URI components.
$uri = [uri] 'http://localhost:9200/index'
$uri.GetLeftPart('Authority')
# or as a one-liner:
([uri] 'http://localhost:9200/index').GetLeftPart('Authority')
Output:
http://localhost:9200
By passing other values from the UriPartial enum, different parts of the URI can be returned:
$uri = [uri] 'http://localhost:9200/index?param=value#anchor'
foreach( $part in 'Scheme','Authority','Path','Query' ) {
[pscustomobject]@{
Part = $part
URI = $uri.GetLeftPart( $part )
}
}
Output:
Part URI
---- ---
Scheme http://
Authority http://localhost:9200
Path http://localhost:9200/index
Query http://localhost:9200/index?param=value
As noted by this related C# answer, there is one catch with Uri.GetLeftPart()
:
If the port is the default port for the scheme, it will strip it out. E. g., the URI http://localhost:80/index
gets turned into http://localhost/index
, because port 80 is the default for the HTTP scheme.
If this is a problem, then you may use the UriBuilder
class to manually build the new URI from the parts of the original URI, while avoiding direct string manipulation:
Function Get-UriBase( [Parameter(Mandatory, ValueFromPipeline)] [Uri] $Uri ) {
process {
$uriBase = [UriBuilder]::new( $uri.Scheme, $uri.Host, $uri.Port ).ToString()
# Output $uriBase if original URI starts with this part
if( $uri.OriginalString.StartsWith( $uriBase ) ) {
return $uriBase
}
# Otherwise original URI didn't contain a port, so use GetLeftPart() which omits it
$uri.GetLeftPart('Authority')
}
}
foreach( $uri in 'http://localhost:80/index', 'http://localhost:1234/index', 'http://localhost/index' ) {
# For output in table format
[PSCustomObject]@{ URI = $uri; URI_Base = Get-UriBase $uri }
}
Output:
URI URI_Base
--- --------
http://localhost:80/index http://localhost:80/
http://localhost:1234/index http://localhost:1234/
http://localhost/index http://localhost