6

I'd like to script the management of Docker containers, but I find it difficult to pass PS variables to Docker commands, in particular due to path format differences.

The following line (*) and the likes you can find here do work, however they are inconvenient:

Start-Process docker " run --rm -v $($env:USERPROFILE -replace '\\','/'):/data alpine ls /data"

Indeed, PS Start-Process is perfect for an MSI installer where you need to see the popup and to control its level of visibility so as to understand that a silent installer is going. Instead, you don't want to start a new window each time you run a console app and particularly in Docker, where you interact back and forth with caller and called shell.

To "Run a command, script, or script block" PS specifically provides &, "the call operator, also known as the 'invocation operator'". However, I attempted without success with:

& docker run --rm -v $($env:USERPROFILE -replace '\\','/'):/data alpine ls /data

Cmd.exe would perhaps make things easier, but PowerShell is the official shell to interact with Docker for Windows. Thus, there should be a reliable way to pass variable arguments to Docker commands.

(*) The remove switch -rm is used here only for the purpose of experimenting with the answer avoiding cluttering your workspace. Of course, I do not usually destroy the container as soon as I create it, but rather interact with it passing -ti.

EDIT

@AnsgarWiechers proposes parameters splatting in a comment:

$params = 'run',  '--rm', "-v $($env:USERPROFILE -replace '\\','/'):/data", 'alpine', 'ls /data'
docker  @params

Assuming I am implementing it properly, it doesn't work either and gives:

C:\Program Files\Docker\Docker\Resources\bin\docker.exe: Error response from daemon: invalid mode: /data.        
See 'C:\Program Files\Docker\Docker\Resources\bin\docker.exe run --help'.                                        
antonio
  • 10,629
  • 13
  • 68
  • 136
  • not sure how this is duplicate if he is asking about differences in path: `/` vs `\ ` – 4c74356b41 Feb 03 '18 at 16:52
  • @4c74356b41 Passing variables and parameter handling in general is much easier when using the call operator and splatting instead of trying to fit things into `Start-Process`. – Ansgar Wiechers Feb 03 '18 at 17:21
  • ok, but he is not asking for that? @AnsgarWiechers – 4c74356b41 Feb 03 '18 at 17:22
  • He may not be asking for it, but I'm pretty certain that it's the actual solution for his problem. – Ansgar Wiechers Feb 03 '18 at 17:40
  • @AnsgarWiechers: OP there asks for a solution to start several MSI processes synchronously. One does not want to interact with a silent MSI installer, so `Start-Process` is OK and its popups can even help catching errors. I propose myself `Start-Process` approach which "works", but clearly state it is "inconvenient". Your console approach is not what the OP asked and gave explicit explanations why wants a `Start-Process` solution. Therefore those who are looking for solutions not based on `Start-Process` will not look there and those who are willing to answers are not likely to post either. – antonio Feb 03 '18 at 20:22
  • @AnsgarWiechers: Even assuming OP had asked to run the MSI sequences without `Start-Process` (which clearly is not the case), you assume this is a PS question only, instead it is a Docker question too. There are a number of Windows/Linux interoperability issues that simply do not matter with MSIs: non-unix paths; Docker commands might themselves use conflicting $-variables, specific Docker switches to pass variables, the called docker app might allocate a pseudo-TTY, to mention a few. These issues suggest specific answers to my question, which go beyond the relatively trivial MSI command line. – antonio Feb 03 '18 at 20:24
  • `$params = 'run', '--rm', '-v', "//$($env:USERPROFILE -replace '\\','/' -replace ':'):/data", 'alpine', '"ls /data"'`. Also, [maybe related](https://stackoverflow.com/a/33151452/1630171). – Ansgar Wiechers Feb 03 '18 at 21:25
  • Hmm... I see contradictory information about how to mount volumes from a Windows host into a Linux container. Some sources say `//c/some/folder:/mount/point`, others `C:/some/folder:/mount/point`. The sources claiming the latter mention a requirement to [define the drive as a shared volume](https://github.com/moby/moby/issues/18756#issuecomment-244913812) first. In that case `"$($env:USERPROFILE -replace '\\','/')"` should suffice. – Ansgar Wiechers Feb 03 '18 at 21:54
  • And to be clear, it doesn't really matter much which command exactly you or the other OP want to run, both questions are about executing an external command with parameters from PowerShell. The recommended way of doing that is invoking the executable via the call operator and passing the parameters via splatting. Which is why I marked this question as a duplicate of the other question. – Ansgar Wiechers Feb 03 '18 at 22:03
  • @4c74356b41: I am still clueless on how I should apply splatting to Docker calls, so I opened an [issue](https://meta.stackoverflow.com/q/363306/1851270) on meta. – antonio Feb 12 '18 at 22:54
  • So i launch my containers like so: `docker run -v B:\folder\otherfolder\:/home/folder ...` and this mapping works – 4c74356b41 Feb 13 '18 at 06:02
  • @4c74356b41: This works for me too, but how can you make your path relative to `$env:USERPROFILE`? Or, more in general, how can you pass paths as variables? – antonio Feb 13 '18 at 14:08

1 Answers1

5

There is no need for parameter splatting or even the call operator, double-quoting solves:

docker run --rm -v "$($env:USERPROFILE -replace '\\','/'):/data" alpine ls /data
antonio
  • 10,629
  • 13
  • 68
  • 136
  • for cwd/pwd: `... -v "$($pwd.path -replace '\\','/'):/data ..."` — in official docs there's only linux version which is (slightly editted to fit this scenario) `...-v "$(pwd)":/data...` — see https://docs.docker.com/storage/bind-mounts/#start-a-container-with-a-bind-mount – pavol.kutaj Dec 04 '21 at 06:34