is there a way to make batch code more compact? - powershell

I am trying to create a 1 line code which downloads files and executes them. I have tried the & and && method to run more commands one after another. but I am having a hard time trying to put the second line with the first one using &.
powershell -Command "Invoke-WebRequest https://github.com/-----/unixC/archive/main.zip -OutFile I.zip" & powershell Expand-Archive I.zip & for /f %%a IN ('dir "I\unixC-main" /b') do move "I\unixC-main\%%a" "%cd%\"
#RD /S /Q "I" & del /q /f I.zip log.txt README.md & start unixC.bat & start /b "" cmd /c del "%~f0"&exit /b
Is there any way to make this snippet of code even shorter? and more compact?
Rasil

Like others have said, the whole thing could be done in powershell. Semicolon seperates commands. -command is the default so you can leave it out. Wget is a powershell alias for invoke-webrequest.
powershell wget https://github.com/-----/unixC/archive/main.zip -OutFile I.zip; Expand-Archive I.zip
Example powershell replacement for the whole thing:
Invoke-WebRequest https://github.com/-----/unixC/archive/main.zip -OutFile I.zip
Expand-Archive I.zip
move-item i\unixC-main\* $pwd # $pwd is optional
remove-item -recurse i
remove-item -force i.zip,log.txt,readme.md
.\unixC.bat
remove-item $args[0]

Try parenthesising for /f %%a IN ('dir "I\unixC-main" /b') do move "I\unixC-main\%%a" "%cd%\" and then append the &{second line}

Related

PowerShell mask Get-ItemPropertyValue one-liner in batch file

I use PowerShell one-liners in several batch scripts, but seem failing to escape the following one correctly:
if not defined LANGUAGE (
for /f "usebackq" %%v in (`PowerShell.exe -NoProfile -ExecutionPolicy Bypass -Command "(Get-ItemPropertyValue -Path 'HKCU:Control Panel\International\' -Name 'LocaleName').Split('-')[0]"`) do set LANGUAGE=%%v
)
I verified that it is this line that fails in my batch file. The idea behind the code is to read the value from the registry and assign the first part before the hyphen to an environment variable. So if the registry value is "de-DE", LANGUAGE shall have the value of "de".
I cannot reproduce an issue with the code you've provided.
I would however suggest you consider other approaches - compare these examples and note which executes the fastest
#Echo off
Setlocal
For /f "delims=" %%v in ('where /r "%Windir%\SysWOW64\WindowsPowerShell" powershell.exe')Do Set "powershell=%%v -nologo -noprofile"
Echo(%TIME%
For /f "usebackq" %%v in (`PowerShell.exe -NoProfile -ExecutionPolicy Bypass -Command "(Get-ItemPropertyValue -Path 'HKCU:Control Panel\International\' -Name 'LocaleName').Split('-')[0]"`) do set "LANGUAGE=%%v"
Set LANG
Echo(%TIME%
For /f "usebackq tokens=1 Delims=-" %%G in (`
%powershell% -c "Get-ItemPropertyValue -Path 'HKCU:Control Panel\International\' -Name 'LocaleName'"
`)Do Set "LANGUAGE=%%G"
Set LANG
Echo(%TIME%
For /f "Skip=1 tokens=3 Delims=- " %%G in ('reg query "HKEY_CURRENT_USER\Control Panel\International" /v localename')Do Set "LANGUAGE=%%G"
Set LANG
Echo(%TIME%
Endlocal
Goto:Eof

How do I use robocopy to run a powershell elevated copy with spaces in the directory names?

If you find a better question that encompasses my situation, please let me know. I haven't found my case yet.
I tried running an elevated powershell command with:
powershell -command "somecommand -Verb runas"
as
powershell -command "robocopy \\hostess\blab\foo 'C:\Program Files\foo ' /s /e /r:0 /z -Verb runas"
The robocopy part works by itself but then adding powershell causes:
ERROR : Invalid Parameter #7 : "-Verb"
The verb is a parameter of powershell executable and not part of the command parameter
powershell -command "robocopy \\hostess\blab\foo 'C:\Program Files\foo ' /s /e /r:0 /z" -Verb runas
see also https://ss64.com/ps/syntax-elevate.html

Hiding Invoke-WebRequest in a batch

I'm trying to download an exe in my .bat file but I can't hide the output with
$progressPreference = 'silentlyContinue'
| Out-Null
and $null 2>&1.
I don't know why none of them worked.
This is the script that I'm using.
powershell "Invoke-WebRequest http://example.com/example.exe -OutFile "%UserProfileDir%\AppData\LocalLow\example_Data\example.exe"
It downloads the exe perfectly but I can't hide the output.
You can get inspired by this batch file :
#echo off
set URL=https://www.google.tn/images/branding/googlelogo/1x/googlelogo_color_272x92dp.png
set FileName=%~dp0Google_Logo.png
Call :Download %URL% %FileName%
Start "" %FileName% & Exit
::*********************************************************************************
:Download <URL> <FILE>
Powershell.exe -command "(New-Object System.Net.WebClient).DownloadFile('%1','%2')"
exit /b
::*********************************************************************************

Issue with pushd/popd and rebooting

I write the following powershell, which create a bat installer for all drivers from a selected folder, and then should restart the pc.
New-Item C:\Tools\Drivers\DellLatitude3450.bat
Add-Content C:\Tools\Drivers\DellLatitude3450.bat -Value '
pushd C:\Tools\Drivers\
forfiles /p DellLatitude3450 /s /m *.inf /c "cmd /c pnputil -i -a #Path"
rmdir /s /q "C:\Tools\Drivers\DellLatitude3450"
rmdir /s /q "C:\Tools\Drivers\Elevate"
del /f "C:\Tools\Drivers\Elevate.zip"
del /f "C:\Tools\Drivers\DellLatitude3450.bat"
shutdown /r /t 15
popd
'
The bat generated is working great, except for the reboot.
I tried to do the same only creating the bat with shutdown and it works, so I'm missing something related with pushd/popd.
I tested the file creation. Had to add -ItemType 'file' to New-Item, else I got a prompt to enter type.
Main issue:
You are deleting the batch-file before the shutdown command is supposed to execute. Move the delete line down to the bottom of the batch-file code. That should then allow the shutdown command to execute as deleting the batch-file before it reaches the end, will immediately end the batch-file.
The code tested with the batch-file creation:
New-Item C:\Tools\Drivers\DellLatitude3450.bat -ItemType 'file'
Add-Content C:\Tools\Drivers\DellLatitude3450.bat -Value #'
pushd C:\Tools\Drivers\
forfiles /p DellLatitude3450 /s /m *.inf /c "cmd /c pnputil -i -a #Path"
rmdir /s /q "C:\Tools\Drivers\DellLatitude3450"
rmdir /s /q "C:\Tools\Drivers\Elevate"
del /f "C:\Tools\Drivers\Elevate.zip"
shutdown /r /t 15
popd
del /f "C:\Tools\Drivers\DellLatitude3450.bat"
'#
Note: I added here-doc syntax as mentioned at About Quoting Rules even though the single quotes alone seem to work.

Running .cmd/.bat script in Powershell

I'm trying to write and execute a .cmd script in powershell. The code I have for this is:
$script = #'
#echo off
SETLOCAL
CALL something here
'#
Invoke-Expression -Command: $script
This is based off this link which explains the here string in powershell. It's at the bottom of the link. Here's the related msdn.
Here's another related link to someone trying to do the same thing.
I keep getting an error that has to do with including the '#' operator within the string:
Invoke-Expression : At line:1 char:7
+ #echo off
+ ~~~
Unexpected token 'off' in expression or statement.
At line:1 char:1
+ #echo off
+ ~~~~~
The splatting operator '#' cannot be used to reference variables in an expression. '#echo' can be used only as an argument to a command. To reference variables in an expression use '$echo'.
I've tried escaping the '#' symbol, and a plethora of other things. I'd like to know why it seemed to work for them in the third link, but throws this error in my case.
Edit:
Writing to a .bat file then running the bat file resulted in the same error:
$batchFileContent = #'
#echo off
c:\windows\system32\ntbackup.exe backup "C:\Documents and Settings\Administrator\Local Settings\Application Data\Microsoft\Windows NT\NTBackup\data\chameme.bks" /n "1file.bkf1 created 06/09/2013 at 09:36" /d "Set created 06/09/2013 at 09:36" /v:no /r:no /rs:no /hc:off /m normal /j chameme /l:s /f "\\fs1\Exchange Backups$\1file.bkf"
'#
$batchFileContent | Out-File -LiteralPath:"$env:TEMP\backup.cmd" -Force
Invoke-Expression -Command:"$env:TEMP\backup.cmd"
Remove-Item -LiteralPath:"$env:TEMP\backup.cmd" -Force
As Bill Stewart pointed out, I should write the content of the .cmd script in powershell.
Edit:
This
$script = #'
cmd.exe /C "#echo off"
cmd.exe /C "SETLOCAL"
cmd.exe /C "CALL something here"
'#
Invoke-Expression -Command: $script
Seems to work.
This happens because Invoke-Expression interprets your string with PowerShell. PowerShell allows you to run shell commands, but it interprets things as PowerShell first. The # character is the splatting operator in PowerShell.
You should save the commands in a batch file, and then execute that.
Or you can execute single line commands by shelling out to cmd.exe:
Invoke-Expression "cmd.exe /c #echo something"