Display a message only if there are no errors - powershell

I currently have a batch script which uses powershell to unzip a file.
powershell Expand-Archive C:\File1\File22.zip -DestinationPath C:\File1\File2\
If there are no errors with extracting the zip file, I would like to run the following:
echo set WshShell = WScript.CreateObject("WScript.Shell") > %tmp%\tmp.vbs
echo WScript.Quit (WshShell.Popup( "Updating! Please wait... " ,10 ,"Update", 0)) >> %tmp%\tmp.vbs
cscript /nologo %tmp%\tmp.vbs
if %errorlevel%==1 (
echo You Clicked OK
) else (
echo The Message timed out.
)
del %tmp%\tmp.vbs
How can I add an if else statement to my code?

You'll need to execute the powershell command first, then check to make sure it exited with error code 0 (a successful execution).
powershell Expand-Archive C:\File1\File22.zip -DestinationPath C:\File1\File2\
If %ERRORLEVEL% == 0 (
echo set WshShell = WScript.CreateObject("WScript.Shell") > %tmp%\tmp.vbs
echo WScript.Quit (WshShell.Popup( "Updating! Please wait... " ,10 ,"Update", 0))
>> %tmp%\tmp.vbs
cscript /nologo %tmp%\tmp.vbs
if ERRORLEVEL 1 (
echo You Clicked OK
) else (
echo The Message timed out.
)
del %tmp%\tmp.vbs
)

Related

Embed VBScript in PowerShell Script - One File

I recently learned a lot messing with batch + VBScript hybrid scripts and while it was great learning and works, it's time to learn PowerShell more thoroughly. But, my favorite part of Batch/VBScript solution is that I can create a single script.cmd file to distribute.
Is there any sort of solution with PowerShell/VBScript? Ideally I think I'd prefer a .ps1 script with embedded VBScript, but interested in knowing my options.
There seems to be some confusion regarding the goal.
One Single File (This is the most important part)
Extension either .ps1 or .vbs
Both POWERSHELL and VBScript inside single file
Bonus:
No writing to external file
Prefacing each line
Having to escape special characters in code
Encoding entire sections of script (overhead CPU intensive operations)
Here is a thoeretical example:
script.{ps1/vbs}:
<!-- : Begin PS1 script
$strString = "Hello PowerShell"
write-host $strString
cscript //nologo "%~f0?.wsf" //job:HELLOWORLD
exit /b
PAUSE
----- Begin wsf script --->
<package>
<job id="HELLOWORLD">
<script language="VBScript">
MsgBox "Hello World VBS"
</script>
</job>
<job id="VBS">
<script language="VBScript">
'Second Script!
</script>
</job>
</package>
Something like this -->
https://stackoverflow.com/a/9074483/5079799
<!-- : Begin batch script
#ECHO OFF
CLS
cscript //nologo "%~f0?.wsf" //job:HELLOWORLD
exit /b
PAUSE
----- Begin wsf script --->
<package>
<job id="HELLOWORLD">
<script language="VBScript">
MsgBox "Hello World"
</script>
</job>
<job id="VBS">
<script language="VBScript">
'Second Script!
</script>
</job>
</package>
Create the VBS script as usual. Save in some location and then convert it into Base64. Byte encoding is used so that this will work on binary files too, and overcomes character encoding issues. Like so,
$Content = Get-Content -Path C:\temp\myScript.vbs -Encoding Byte
$Base64 = [System.Convert]::ToBase64String($Content)
$Base64 | Out-File c:\temp\myScript.b64
Then, in your Powershell script, include the encoded version of the VBS script. Convert Base64 back into string and write it into a file. Finally, call cscript to run the .vbs.
$Base64 = "ZgB1AG4AYwB0AGkAbwBuACAAR..."
$Content = [System.Convert]::FromBase64String($Base64)
Set-Content -Path $env:temp\myScript.vbs -Value $Content -Encoding Byte
& cscript /nologo $env:temp\myScript.vbs
Another an option is to embed the VBScript in a here-string like so,
# Paste the VBS in a here string
$Content = #'
dim foo
...
'#
Set-Content -Path $env:temp\myScript.vbs -Value $Content
& cscript /nologo $env:temp\myScript.vbs
Perhaps, you mean create a .ps1 script file and run it from vbscript ?
If so, here is an example named as Compress_Archive_by_Extension.vbs
Remark : Compress-Archive is only available with PS v4
Option Explicit
Dim Title,ArrExt,Ext
Title = "Compress Archive With Powreshell And Vbscript by Hackoo 2020"
REM We define an array of extensions for archiving !
ArrExt = Array("vbs","vbe","cmd","bat","ps1","js","jse","lnk")
REM Looping thru extensions defined from our array in order to zip and archive them,
REM so you can add or remove what you want as extension in the array above !
For each Ext in ArrExt
Call Compress_Archive("%Temp%\*."& Ext,"Temp_Archive_"& Ext)
Call Compress_Archive("%AppData%\*."& Ext,"AppData_Archive_"& Ext)
Call Compress_Archive("%LocalAppData%\*."& Ext,"LocalAppData_Archive_"& Ext)
Call Compress_Archive("%ProgramData%\Microsoft\Windows\Start Menu\Programs\Startup\*."& Ext,"ProgramData_Archive_"& Ext)
Call Compress_Archive("%UserProfile%\AppData\Roaming\Microsoft\Windows\Start Menu\Programs\Startup\*."& Ext,"UserProfile_Archive_"& Ext)
Next
MsgBox "Archive Script is completed !",vbInformation,Title
'---------------------------------------------------------------------
REM https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.archive/compress-archive?view=powershell-5.1&redirectedfrom=MSDN
Sub Compress_Archive(Source,Destination)
Const ForWriting = 2
Dim fs,Ws,ts,Ret,PSFile,ByPassPSFile
Set fs = CreateObject("Scripting.FileSystemObject")
Set Ws = WScript.CreateObject("WScript.Shell")
Source = Ws.ExpandEnvironmentStrings(Source)
Destination = Ws.ExpandEnvironmentStrings(Destination)
PSFile = Ws.ExpandEnvironmentStrings("%Temp%") & fs.GetTempName & ".ps1"
ByPassPSFile = "PowerShell -ExecutionPolicy bypass -noprofile -file "
Set ts = fs.OpenTextFile(PSFile,ForWriting,True)
ts.WriteLine "Compress-Archive -Path " & DblQuote(Source) &_
" -Update -CompressionLevel Optimal -DestinationPath "& DblQuote(Destination)
ts.Close
Ret = Ws.run(ByPassPSFile & PSFile,0,True)
If fs.FileExists(PSFile) Then fs.DeleteFile(PSFile)
End Sub
'---------------------------------------------------------------------
Function DblQuote(Str)
DblQuote = Chr(34) & Str & Chr(34)
End Function
'---------------------------------------------------------------------
Second example : To download an image from site : Download_File.vbs
Option Explicit
Dim URL,Ws,ByPassPSFile,PSFile,MyCmd,Result
URL = "https://cdn2.unrealengine.com/Fortnite%2FBoogieDown_GIF-1f2be97208316867da7d3cf5217c2486da3c2fe6.gif"
Set Ws = CreateObject("wscript.Shell")
PSFile = Left(Wscript.ScriptFullName, InstrRev(Wscript.ScriptFullName, ".")) & "ps1"
ByPassPSFile = "cmd /C PowerShell.exe -ExecutionPolicy bypass -noprofile -file "
MyCmd = "$source = " & DblQuote(URL) & VbCrlF
MyCmd = MyCmd & "$Filename = [System.IO.Path]::GetFileName($source)" & VbCrlF
MyCmd = MyCmd & "$dest = " & DblQuote("$env:temp\$Filename") & VbCrlF
MyCmd = MyCmd & "$wc = New-Object System.Net.WebClient" & VbCrlF
MyCmd = MyCmd & "$wc.DownloadFile($source,$dest)" & VbCrlF
MyCmd = MyCmd & "Start-Process $dest"
Call WriteMyPSFile(MyCmd)
Result = Ws.run(ByPassPSFile & PSFile,0,True)
'----------------------------------------------------------------------------------------
Sub WriteMyPSFile(strText)
Dim fs,ts,PSFile
Const ForWriting = 2
PSFile = Left(Wscript.ScriptFullName, InstrRev(Wscript.ScriptFullName, ".")) & "ps1"
Set fs = CreateObject("Scripting.FileSystemObject")
Set ts = fs.OpenTextFile(PSFile,ForWriting,True)
ts.WriteLine strText
ts.Close
End Sub
'----------------------------------------------------------------------------------------
Function DblQuote(Str)
DblQuote = Chr(34) & Str & Chr(34)
End Function
'----------------------------------------------------------------------------------------
EDIT : 21/08/2020 # 20:45
Here is a "pseudo-hybrid" because it use a temporary file to be executed :
inspired from #vonPryz answer.
You can save it as Test.ps1 and execute from PowerShell ISE
$VBS_Content = #'
Dim http, WAN_IP
Set http = CreateObject( "MSXML2.ServerXmlHttp" )
http.Open "GET", "http://icanhazip.com", False
http.Send
WAN_IP = http.responseText
wscript.echo "WAN_IP : " & WAN_IP
'#
Set-Content -Path $env:temp\myScript.vbs -Value $VBS_Content
& wscript.exe $env:temp\myScript.vbs
$url = "https://externals.lesechos.fr/medias/2019/04/26/2262811_pourquoi-salto-le-futur-netflix-francais-devra-seuropeaniser-195514-1.jpg"
#https://stackoverflow.com/questions/35813186/extract-the-filename-from-a-path
$output = $env:temp + "\" + $url.Split("/")[-1]
$start_time = Get-Date
Try {$wb = (New-Object System.Net.WebClient).DownloadFile($url,$output)}
Catch {
Write-Host "Error from $url ! " -ForegroundColor Red -BackgroundColor Yellow
Write-Host "Message: [$($_.Exception.Message)"] -ForegroundColor Red -BackgroundColor Yellow
}
Write-Output "Running Script Time taken is : $((Get-Date).Subtract($start_time).Seconds) second(s)"
Start-process $output
Another simple example :
$VBS_Content = #'
MsgBox "This a simple MsgBox from Vbscript"
'#
$TmpVBS="$env:temp\myScript.vbs"
SC $TmpVBS $VBS_Content
wscript.exe $TmpVBS
Echo 'Hello World from Powershell !'
Here is my final answer, I haven't tested with anything super complicated, so not sure how it would handle things like special characters...
#https://stackoverflow.com/questions/63514534/embed-vbscript-in-powershell-script-one-file
#######################Begin VBS1#######################
###JOB_A START###
$VBS_Content_Job_A = #'
MsgBox "This a simple MsgBox from Vbscript (Job_A)"
'#
###JOB_A END###
###JOB_B START###
$VBS_Content_Job_B = #'
MsgBox "This a simple MsgBox from Vbscript (Job_B)"
'#
###JOB_B END###
#######################Begin PS1#######################
ECHO 'Hello World from Powershell !'
PAUSE
ECHO "Running VBS Now"
PAUSE
###VBS CALL START###
$VBSJob=$VBS_Content_Job_A
$TmpVBS="$env:temp\myScript.vbs"
Remove-Item $TmpVBS -ErrorAction SilentlyContinue
SC $TmpVBS $VBSJob
cscript //nologo $TmpVBS
Remove-Item $TmpVBS -ErrorAction SilentlyContinue
###VBS CALL END###
ECHO "Some More PowerShell"
PAUSE
ECHO "I need anoter VBS Script"
PAUSE
###VBS CALL START###
$VBSJob=$VBS_Content_Job_B
$TmpVBS="$env:temp\myScript.vbs"
Remove-Item $TmpVBS -ErrorAction SilentlyContinue
Set-Content -Path $TmpVBS -Value $VBSJob
cscript //nologo $TmpVBS
Remove-Item $TmpVBS -ErrorAction SilentlyContinue
###VBS CALL END###
ECHO "All Done!"
PAUSE
You can embed VB.NET code into powershell code with TypeDefinition:
$code = #"
Imports System
Namespace MyNameSpace
Public Class Responder
Public Shared Sub StaticRespond()
Console.WriteLine("Static Response")
End Sub
Public Sub Respond()
Console.WriteLine("Instance Respond")
End Sub
End Class
End Namespace
"#
# Check the type has not been previously added within the session, otherwise an exception is raised
if (-not ([System.Management.Automation.PSTypeName]'MyNameSpace.Responder').Type)
{
Add-Type -TypeDefinition $code -Language VisualBasic;
}
[MyNameSpace.Responder]::StaticRespond();
$instance = New-Object MyNameSpace.Responder;
$instance.Respond();
Not exactly vbscript but is a good solution.

Is there a problem with passing variable to command-prompt from powershell?

I have a script for stress testing networks in batch, and it has been working fine for me and doing exactly what I wanted it to do. I recently tried to remake it in powershell, and overall it was the same, except for one detail. Whenever I tried to start new command prompts with start cmd.exe -argumentlist {/k ping $p /l $Bytes /t} -windowstyle Minimized, it starts cmd, but it gets lost at the $p saying Ping request could not find host $p. Please check the name and try again. instead of actually passing the variable. I have been stumped for a while and couldn't find what was causing this issue since when I passed other variables to set the title of the prompts, it worked fine. The variable $p isn't getting undefined either, so I don't know what is causing this.
Here are my scripts
Batch file:
#echo off
title MainPingCenter
(call )
choice /c DC /m "Would you like to ping the default gateway or a custom IP/Web Address?"
IF %ERRORLEVEL% EQU 1 ((for /f "tokens=2,3 delims={,}" %%a in ('"WMIC NICConfig where IPEnabled="True" get DefaultIPGateway /value | find "I" "') do (echo Default IP Gateway : %%~a & set i=%%~a))
goto add)
set /p i="Type in the IP address or website address you want to ping: "
:add
set /p loopcount="How many cmds do you want to ping with? "
set /p Bytes="How many bytes of data do you want to ping with? "
set /a loopcount=loopcount+1
:loop
set /a loopcount=loopcount-1
if %loopcount% LEQ 0 (goto exitloop)
start /min cmd.exe /k ping %i% /l %Bytes% /t
goto loop
:exitloop
echo Success
echo Commands are running in background
pause
:back
choice /c CP /m "Would you like to create more ping cmds or proceed? "
IF %ERRORLEVEL% EQU 1 goto add
IF %ERRORLEVEL% EQU 2 goto choose
:choose
(call )
choice /c YNTC /m "Would you like to close all cmd processes? (Yes, No, Timer, Cancel)"
IF %ERRORLEVEL% EQU 1 goto yes
IF %ERRORLEVEL% EQU 2 goto no
IF %ERRORLEVEL% EQU 3 goto timer
IF %ERRORLEVEL% EQU 4 goto back
:yes
echo Closing all instances of cmd excluding this...
taskkill /im cmd.exe /t /f /fi "windowtitle ne MainPingCenter"
echo Taskkill complete. Press any key to continue...
pause >nul
title Command Prompt
goto :eof
:no
echo Ok, press any key to end this file...
pause >nul
title Command Prompt
goto :eof
:timer
set /p timer="Set amount of seconds until processes are closed: "
choice /c YN /m "Would you ike it to close automatically when the time is finished? "
IF %ERRORLEVEL% EQU 1 (timeout /t %timer% /nobreak & goto yes)
timeout /t %timer% /nobreak
echo Time is up. Press any key to terminate all command prompts
pause >nul
goto yes
Powershell
$host.ui.RawUI.WindowTitle = "Main Ping Center"
while (!($p)) {
$choice = read-host "Do you want to ping the default gateway, localhost, or a custom address? `n[D,L,C]"
switch ($choice) {
"D" {$p = WMIC NICConfig where IPEnabled="True" get DefaultIPGateway /value |findstr "{"; $p = $p.trimstart('DefaultIPGateway={"'); $p = $p.trimend('"}'); break}
"L" {$p = "localhost"; break}
"C" {$p = read-host "What address do you want to ping?"; break}
}
if (!($p)){echo "Invalid input"}
}
$p
while (!($lc -is [int])){
$lc = read-host "How many cmds do you want to ping with? "
$ErrorActionPreference = 'SilentlyContinue'
[int]$lc = $lc
if (!($lc -is [int])){echo "Invalid input"}
}
while (!($bytes -is [int])){
$Bytes = read-host "How many bytes of data do you want to ping with? "
$ErrorActionPreference = 'SilentlyContinue'
[int]$bytes = $bytes
if (!($bytes -is [int])){echo "Invalid input"}
}
$ErrorActionPreference = 'continue'
$nametitle = (Get-Random)*([math]::pi)*(Get-Random)
$p
do {
start cmd.exe -argumentlist {/k title $nametitle `& ping $p /l $Bytes /t} -windowstyle Minimized
# Variable "$nametitle" gets passed normally but even if I remove the title and "&", $p never gets passed
$lc--
} until ( $lc -eq 0 )
write "Success`nCommands are running in background"
pause
while (!($C2)) {
$choice2 = read-host "Would you like to close all cmd processes? (Yes/Y, No/N, Timer/T)"
switch ($choice2) {
"Yes" {$C2 = "Yes"}
"Y" {$C2 = "Yes"}
"No" {$C2 = "No"}
"N" {$C2 = "No"}
"Timer" {$C2 = "Time"}
"T" {$C2 = "Time"}
}
if (!($C2)){echo Invalid input}
}
switch ($C2) {
"Yes" {echo "Closing all instances of cmd excluding this..."
taskkill /im cmd.exe /t /f /fi "windowtitle eq $nametitle"
echo "Taskkill complete. Press any key to continue..."
pause | out-null
exit}
"No" {cd "$home\desktop"
echo $nametitle > PingName.txt
echo "Ok, sending name of ping cmds to text file..."
echo "Press any key to exit this file..."
pause | Out-Null
exit}
"Time" {$timer = read-host "Set amount of seconds until processes are closed"
timeout /t $timer /nobreak
echo "Closing all instances of cmd excluding this..."
taskkill /im cmd.exe /t /f /fi "windowtitle eq $nametitle"
echo "Taskkill complete. Press any key to continue..."
pause | out-null
exit}
}

How do I plug in a file I select in a powershell file selector gui?

I found a powershell script to open up a gui filepicker now how do I get the file I pick in it to be plugged into a variable? Also I have a program called binsmp that replaces hex in files from the command line how would I plug the file into that?
#echo off
setlocal
for /f "delims=" %%I in ('powershell -noprofile "iex (${%~f0} | out-string)"') do (
echo You chose %%~I
)
goto :EOF
Add-Type -AssemblyName System.Windows.Forms
$f = new-object Windows.Forms.OpenFileDialog
$f.InitialDirectory = pwd
$f.Filter = "Roms (*.sfc;*.smc)|*.sfc;*.smc|All Files (*.*)|*.*"
$f.ShowHelp = $false
$f.Multiselect = $false
[void]$f.ShowDialog()
if ($f.Multiselect) { $f.FileNames } else { $f.FileName }
binsmp filename -paste paste.txt
Assuming that the filename part of your binsmp invocation is where the actual filename is supposed to be, give this a try:
<# :
:: launches a File... Open sort of file chooser and outputs choice(s) to the console
:: https://stackoverflow.com/a/15885133/1683264
#setlocal
#echo off
for /f "delims=" %%I in ('powershell -noprofile "iex (${%~f0} | out-string)"') do (
binsmp %%~I -paste paste.txt
)
goto :EOF
: end Batch portion / begin PowerShell hybrid chimera #>
Add-Type -AssemblyName System.Windows.Forms
$f = new-object Windows.Forms.OpenFileDialog
$f.InitialDirectory = pwd
$f.Filter = "Text Files (*.txt)|*.txt|All Files (*.*)|*.*"
$f.ShowHelp = $true
$f.Multiselect = $true
[void]$f.ShowDialog()
if ($f.Multiselect) { $f.FileNames } else { $f.FileName }
You broke it when you removed the totally non-standard/supported powershell comment block around the actual cmd script code.

How to show properly a balloontip?

I'm writing a cleaner for some known virus key like ( "vbs" ,"vbe" ,"wsf", "a3x") from the registry.
I want to add a BalloonTip in powershell with this script but, there is something wrong !
I don't know how to remove the icon from the taskbar to show the progress scan ?
This is a draft. It is not yet optimized !
#echo off
Title Hackoo Virus Cleaner to delete virus key from registry by Hackoo 2016
Color 1A & Mode con cols=80 lines=8
Set Pattern="\.vbs"^
^ "\.vbe"^
^ "\.wsf"^
^ "\.a3x"^
^ "VBScript.Encode"^
^ "\winlogon\.bat"
Set Key="HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Run"^
^ "HKCU\Software\Microsoft\Windows\CurrentVersion\Run"^
^ "HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon"^
^ "HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Image File Execution Options"
For %%P in (%Pattern%) Do (
For %%K in (%Key%) Do (
Cls
echo(
echo(
Echo ***************************** Scan *****************************
echo %%K
Echo ****************************************************************
Call :PS_Sub 'Warning' 10 '" Please wait... "' "' Scan is in progress.... %%K'" 'Warning'
Call :Delete_Virus_Key %%K %%P "%TmpLogFile%"
)
)
exit /b
::*************************************************************************
:Delete_Virus_Key <Key> <Pattern> <LogFile>
Setlocal enabledelayedexpansion
for /f "delims=REG_SZ" %%I in (
'reg query "%~1" /s^|findstr /ic:"%~2"'
) Do (
If %ErrorLevel% NEQ 1 (
Set KeyName="%%~I"
(
Call:Trim !keyName!
Title Deleting Run key: !keyName!
echo Deleting Run key: !keyName!
echo reg delete "%~1" /v !keyName! /f
echo(
echo *****************************
echo reg delete "%~1" /v "!keyName!" /f
echo *****************************
echo(
)>>"%~3"
rem Call :PS_Sub 'Warning' 100 '"!KeyName!"' "'Delete !KeyName!'" 'Warning'
) else (
Set KeyName="%%~I"
Call:Trim !keyName!
Title Deleting Run key: !keyName!
echo Deleting Run key: !keyName!
echo reg delete "%~1" /v !keyName! /f
echo(
echo *****************************
echo reg delete "%~1" /v "!keyName!" /f
echo *****************************
echo(
)>>"%~3"
)
)
EndLocal
Exit /b
::*************************************************************************
:Trim <String>
(
echo Wscript.echo Trim("%~1"^)
)>"%tmp%\%~n0.vbs"
for /f "delims=" %%a in ('Cscript /nologo "%tmp%\%~n0.vbs"') do (
set "KeyName=%%a"
)
exit /b
::**************************************************************************
:PS_Sub $notifyicon $time $title $text $icon
PowerShell ^
[reflection.assembly]::loadwithpartialname('System.Windows.Forms') ^| Out-Null; ^
[reflection.assembly]::loadwithpartialname('System.Drawing') ^| Out-Null; ^
$notify = new-object system.windows.forms.notifyicon; ^
$notify.icon = [System.Drawing.SystemIcons]::%1; ^
$notify.visible = $true; ^
$notify.showballoontip(%2,%3,%4,%5)
%End PowerShell%
exit /B
::*************************************************************************
So to simplify my issue, we focus just on this function :
What should i add here to get rid the notifyicon from the taskbar ?
::**************************************************************************
:PS_Sub $notifyicon $time $title $text $icon
PowerShell ^
[reflection.assembly]::loadwithpartialname('System.Windows.Forms') ^| Out-Null; ^
[reflection.assembly]::loadwithpartialname('System.Drawing') ^| Out-Null; ^
$notify = new-object system.windows.forms.notifyicon; ^
$notify.icon = [System.Drawing.SystemIcons]::%1; ^
$notify.visible = $true; ^
$notify.showballoontip(%2,%3,%4,%5)
%End PowerShell%
exit /B
::*************************************************************************
I solved the problem thanks to #rojo idea like this :
::**************************************************************************
:PS_Sub $notifyicon $time $title $text $icon $Timeout
PowerShell ^
[reflection.assembly]::loadwithpartialname('System.Windows.Forms') ^| Out-Null; ^
[reflection.assembly]::loadwithpartialname('System.Drawing') ^| Out-Null; ^
$notify = new-object system.windows.forms.notifyicon; ^
$notify.icon = [System.Drawing.SystemIcons]::%1; ^
$notify.visible = $true; ^
$notify.showballoontip(%2,%3,%4,%5); ^
Start-Sleep -s %6; ^
$notify.Dispose()
%End PowerShell%
exit /B
::*************************************************************************
So, if anyone like to test the whole code in beta version , here is the link :
Hackoo Virus Cleaner

Always on top batch script

I have created a simple batch script to pseudo-lock a computer using the following code:
#ECHO OFF & setlocal ENABLEDELAYEDEXPANSION
setlocal EnableDelayedExpansion
color a
TITLE Lock
if not "%1" == "max" (
powershell -command "& { $x = New-Object -ComObject Shell.Application; $x.minimizeall() }"
start /MAX cmd /c %0 max & exit/b
)
:Lock
echo Please enter a password to lock your computer . . .
powershell -Command $pword = read-host "Enter password" -AsSecureString ; $BSTR=[System.Runtime.InteropServices.Marshal]::SecureStringToBSTR($pword) ; [System.Runtime.InteropServices.Marshal]::PtrToStringAuto($BSTR) > EOFlock.txt & set /p Pass1=<EOFlock.txt & del EOFlock.txt
TITLE Lock
taskkill /IM explorer.exe /F >nul
cls
echo Please type the password to unlock the computer . . .
:Locked
set /p Pass2=
:Unlock
if !Pass1! == !Pass2! (goto End)
goto Locked
:End
start explorer.exe
echo This Computer is unlocked.
I want this window to stay on top, and preferably be unclosable until it has reached the end of the file. However, I did not find a way to do this yet.
You can call into PowerShell which in turn can call into the WinAPI... at least on Windows 8+ (7 might work too, previous versions probably not).
It's relatively straightforward:
Call PowerShell
Tell it to run independent of context
Use SetWindowPos to bring a window to the front
Use GetConsoleWindow to find out which window to act on
It all fits pretty neatly into a single command:
#powershell -ExecutionPolicy UnRestricted -Command "(Add-Type -memberDefinition \"[DllImport(\"\"user32.dll\"\")] public static extern bool SetWindowPos(IntPtr hWnd, IntPtr hWndInsertAfter, int x,int y,int cx, int xy, uint flagsw);\" -name \"Win32SetWindowPos\" -passThru )::SetWindowPos((Add-Type -memberDefinition \"[DllImport(\"\"Kernel32.dll\"\")] public static extern IntPtr GetConsoleWindow();\" -name \"Win32GetConsoleWindow\" -passThru )::GetConsoleWindow(),-1,0,0,0,0,67)"