The DOS environment is a series of ASCIIZ strings and ending with one more zero plus an obscure word of some kind. Hereafter you have the name of the currently running program as an ASCIIZ string.
To get the name of the currently running .COM file use next code:
  .model tiny
  .code
  ORG 256
Begin:
  mov ax, word ptr [002Ch]  ; Segment of the DOS environment DOES NOT WORK IN TASM
  mov ds, ax                ;                                SEE [EDIT 2]
  xor si, si
  cld
  jmp StartSearch
SkipEntry:
  lodsb
  cmp al, 0
  jne SkipEntry
StartSearch:
  lodsb
  cmp al, 0
  jne SkipEntry         ; Go skip an environment string
  ; End of environment
  lodsw            ; ???
  ;Here `DS:SI` points at the name of the running program (path included).
  ; Copy
  mov di, offset Buffer
Again:
  movsb
  cmp byte ptr [si], 0
  jne Again
  ; Restoring DS
  push es
  pop  ds
  mov byte ptr [di], "$"
  ; Printing path
  mov dx, offset Buffer
  mov ah, 09h
  int 21h
  ; Wait key and end
  mov ah, 00h
  int 16h
  mov ax, 4C00h
  int 21h
Buffer db 256 dup (0)
  END Begin
I tested the program in DOSBox 0.74 and results are OK.
[edit 1]
From comments I see that the issue is not yet resolved even though, you too, run the code in DOSBox. I suggest you use the FASM assembler that you can download at https://flatassembler.net. It's the easiest assembler around and it's a one-step compiler, meaning there's no separate linking required.
This is the adapted source for our current program:
  ORG 256          ; FASM automatically 'knows' that you want a .COM program
                   ; No '.model' or so needed
Begin:
  mov ds, [002Ch]  ; Segment of the DOS environment
  xor si, si
  cld
  jmp StartSearch
SkipEntry:
  lodsb
  cmp al, 0
  jne SkipEntry
StartSearch:
  lodsb
  cmp al, 0
  jne SkipEntry    ; Go skip an environment string
  ; End of environment
  lodsw            ; ???
  ;Here `DS:SI` points at the name of the running program (path included).
  ; Copy
  mov di, Buffer
Again:
  movsb
  cmp byte [si], 0
  jne Again
  ; Restoring DS
  push es
  pop  ds
  mov byte [di], "$"
  ; Printing path
  mov dx, Buffer
  mov ah, 09h
  int 21h
  ; Wait key and end
  mov ah, 00h
  int 16h
  mov ax, 4C00h
  int 21h
Buffer db 256 dup (0)
In FASM (just like in NASM), mov dx, Buffer gives the (offset) address of the Buffer variable, whereas mov dx, [Buffer] gives the value stored IN the Buffer variable. This is one of most important differences if you're coming from MASM or TASM.
The executable that FASM produces will have 306 bytes.
[edit 2]
mov ax, word ptr [002Ch]
mov ds, ax
The instruction mov ax, word ptr [002Ch] does not do what we needed.
In TASM, neither the presence of the square brackets, nor even the mention of word ptr turn this into a read from memory. It gets encoded as an immediate load to AX (B8,2C,00).
For our program it means that we will be looking at the many zeroes stored at offset 02C0h in the Interrupt Vector Table.
Working alternatives include (both require 5 bytes):
- Using a register addresses memory -   mov bx, 002Ch          ; BB,2C,00
  mov ds, [bx]           ; 8E,1F
 
- Using a (redundant) segment override addresses memory -   mov ds, cs:[002Ch]      ; 2E,8E,1E,2C,00
 
Read more about this peculiar TASM syntax in:
Confusing brackets in MASM32