There are three things to take note of your script:
You have to make sure if you've been given a status; if not, make the running client give you one. Your existing code will give out status regardless of whether you're already one or not. A check for that would be nice.
For your part command, you can specify a $2 so the client running the code will part the channel you choose. Conversely, if no $2 has been specified, part the current channel.
Below is an example using /goto without the use of one if statement per command, along with checks added:
on @Owner:TEXT:*:#: {
var %x $1 | goto %x
:!voice | mode $iif($nick !isvoice #,$v2 +v $v1) | halt
:!devoice | mode $iif($nick isvoice #,$v2 -v $v1) | halt
:!op | mode $iif($nick !isop #,$v2 +o $v1) | halt
:!deop | mode $iif($nick isop #,$v2 -o $v1) | halt
:!halfop | mode $iif($nick !ishelp #,$v2 +h $v1) | halt
:!dehalfop | mode $iif($nick ishelp #,$v2 -h $v1) | halt
:!protect | mode # $iif(!$nick(#,$nick,&),+a $nick) | halt
:!deprotect | mode # $iif($nick(#,$nick,&),-a $nick) | halt
:!join | join $$2 | halt | :!nick | nick $$2 | halt
:!part | part $iif(!$2,#,$iif($2 ischan,$v1)) | halt
:!commands | msg $nick My commands are: !voice, !op, !join, $&
!part, !halfop, !dehalfop, !protect, !deprotect, !devoice, !deop, !nick
:%x | return
}
P.S. you should make sure the running client is opped by adding a @ prefix to your text event.