bat 與 PowerShell 的結合使用



前言

背景: 前前段時間,做文件操作處理時,有這么一個場景: window 下需要對某固定目錄下的文件及其他文件進行拷貝操作, 至目標對象---> 外置存儲設備(U盤或移動硬盤),且需要一定大小的存儲量並做判斷提示。
問題: 其主要問題不在文件拷貝操作,而是對外置存儲設備的處理(主要是對磁盤大小的判斷,也就是數字的比較及計算)。首先批處理的數字處理有一定范圍(正負 2^31-1),其次超出范圍的比較情況還有不同。
解決: 其一則是正面剛(截取操作再比較),其二則是繞過換其他方法(調 PowerShell 處理)

一、使用 bat 做數字比較

1.下圖為批處理數字比較的情況:兩個值都超出范圍的比較,結果相反

2.以下為當時的腳本(后面磁盤大小的計算實在不知道咋怎,用了 PowerShell ):

@echo off & setlocal enabledelayedexpansion
rem =========================================================
rem ==  The tools develop for copy files to external disk  ==
rem	==			author: by zzw							   ==
rem ==			datetime: 2019.07.1                        ==
rem =========================================================

@rem chcp 936 ::更換默認編碼

@rem 源路徑
set srcPath=F:\zzwTest

@rem 本地磁盤驅動器: C:\ D:\ E:\
:HasDrive
for /f "tokens=1,* delims= " %%i in ('fsutil fsinfo drives') do (
	set d=%%j
	set d=!d:\=!
	@rem echo !d!. 遍歷磁盤信息是否包含 移動 字符
	for %%a in (!d!) do (
		fsutil fsinfo driveType %%a | findstr "移動" >nul && set driver=%%a
	)
	
	@rem 移動硬盤會被指定為固定驅動器.需要去除本地磁盤
	if not defined driver (
		set d=!d:C:=!
		set d=!d:D:=!
		set d=!d:E:=!
		set d=!d: =!
		set driver=!d!
		if "!d!"=="" ( call :Tip1 ) else ( call :Tip1 ZZW )
	)
	goto DriverSpace
)

:DriverSpace
if defined driver (
	@rem 包含 可用字節總數 的行,取第一行
	for /f "tokens=1,2 delims=:" %%i in ('fsutil volume diskFree %driver% ^|findstr "可用字節總數"') do (
		set free=%%j
		@rem echo !free! | findstr "(" && set free=!free:*(=! & set free=!free:^)=! || set free=!free: =!
		for /f "tokens=1 delims= " %%x in ("!free!") do (
			set free=%%x
		)
		@rem calculate disk size. multiplier of 1.1
		@rem debug: set free=1048576000
		if !free! LSS 1126 ( call :Tip3 1 B )
		if !free! LSS 1153433 ( call :Tip3 1024 KB )
		if !free! LSS 1181116006 ( call :Tip3 1024*1024 MB )
		call :Tip3 1024*1024*1024 GB
		
		:Below
		@rem 批處理數值范圍在正負 2^31-1 = 2147483647
		set total=!free!t
		if "!total:~10!"=="" (
			@rem echo 小於 10 位數 0.93GB=999999999B  0.5GB=536870912B
			if "!total:~8!"=="" ( call :Tip2 [10MB] ★★★警告★★★)
			if "!total:~9!"=="" ( call :Tip2 [100MB] ★★★警告★★★)
			set totalN=!total:~0,9!
			if !totalN! LSS 104857600 ( call :Tip2 [100MB] ★★★警告★★★)
			if !totalN! LSS 262144000 ( call :Tip2 [250MB] ★★★警告★★★)
			if !totalN! LSS 536870910 ( call :Tip2 [500MB] ★★★警告★★★)
			call :Tip2 [1GB]
		)
		if "!total:~10!"=="t" ( 
			@rem echo 等於 10 位數 6GB=6442450944B
			set totalA=!total:~0,10!
			if !totalA! LSS 1048576000 ( call :Tip2 [1GB] )
			if !totalA! LSS 1610612735 ( call :Tip2 [1.5GB] )
			if !totalA! LSS 2147483646 ( call :Tip2 [2GB] )
			set totalB=!total:~0,9!
			if !totalB! LSS 268435456 ( call :Tip2 [2.5GB] )
			if !totalB! LSS 322122547 ( call :Tip2 [3GB] )
			if !totalB! LSS 429496729 ( call :Tip2 [4GB] )
			if !totalB! LSS 536870912 ( call :Tip2 [5GB] )
			if !totalB! LSS 644245094 ( call :Tip2 [6GB] )
		)
		goto ReSelect
	)
)

:Tip1
color 0b & echo, 
echo 	請確保外置 [U盤] 或 [移動硬盤] 插入成功!!!& echo,
if not "%1"=="" ( echo 	磁盤識別錯誤,請聯系開發者 ----^> %1& echo, )
goto End

:Tip2
color 0b & echo, 
echo 	請確保 %driver% 盤空間至少 6GB 可用 & echo,
if not "%2"=="" echo 	%2
echo 	注意 %driver% 盤空間小於 %1 ,不建議繼續操作,默認 N 
echo 	若繼續將可能導致部分文件復制失敗!!!
echo,
set /p confirm=請確認是否要繼續(N/Y)_^>^>
if /i %confirm%==y goto ReSelect
goto End

:Tip3
set /p =◆ %driver% 磁盤可用空間(約)為: <nul
@rem powershell -c "[String]$i=!free!/(%1);if($i.contains('.')) {$s=$i.split('.'); $s[0],$s[1].substring(0,3)+'%2' -join('.')} else {$i+'%2'}"
powershell -c "[String]$i=!free!/(%1);if($i.contains('.')) {$s=$i.split('.'); $s[0]+'.'+$s[1].substring(0,3)+' %2'} else {$i+'%2'}"
goto Below

:ReSelect
color 0a
echo,
echo *********該工具將拷貝所選目錄文件至 %driver% 盤設備********
echo,
echo 	請在下列選項中選擇需要操作的路徑(如: 1 、2 、3 )
echo,
echo ==========================================================
set a=0
for /f %%i in ('dir /b /ad "%srcPath%"') do (
	set /a a+=1
	echo 	[!a!] %%i
)
echo,
echo ==========================================================
set a=0
set /p number=請輸入:
for /f %%i in ('dir /b /ad "%srcPath%"') do (
	set /a a+=1
	if !a!==%number% set testResult=%%i & echo, & echo 你的選擇是 %%i
)
if not defined testResult (
	color 04
	echo,
	echo 請選擇正確的選項!
	echo 請按任意鍵重新選擇!
	pause >nul & cls & goto ReSelect
)
echo,

echo "=====可以開始操作了======"

:End
pause

從以上腳本看來,在 cmd 中使用大的數據比較時非常吃力,腳本還一坨一坨的。而 PowerShell 則簡單了,請看下列分析及操作操作。

二、CMD 命令行 PowerShell 的使用

在使用前首先來介紹下:
Windows PowerShell 是一種命令行外殼程序和腳本環境,使命令行用戶和腳本編寫者可以利用 .NET Framework的強大功能 ----->百度百科

1.在cmd 命令行中 powershell /? 先查看簡要幫助文檔(以下為比較關注信息),這里順便貼上官方路徑

2.若要運行PowerShell 腳本或者命令,可能需要使用 PowerShell 需要開啟相關權限,如下操作即可:

@echo off

@rem set the execution mode of the PowerShell
set flag=1
@rem -c 等同 -Command
powershell -c "Get-ExecutionPolicy" |findstr "Restricted" >nul && set flag=0
if %flag% == 0 ( 
        :: powershell -ExecutionPolicy RemoteSigned  與下句等同
	powershell -c "Set-ExecutionPolicy RemoteSigned" 
	echo Allowed to use powershell
)

3.着重實踐下重點關注的地方

PowerShell[.exe] [-PSConsoleFile <file> | -Version <version>]
    [-NoLogo] [-NoExit] [-Sta] [-NoProfile] [-NonInteractive]
    [-InputFormat {Text | XML}] [-OutputFormat {Text | XML}]
    [-WindowStyle <style>] [-EncodedCommand <Base64EncodedCommand>]
    [-File <filePath> <args>] [-ExecutionPolicy <ExecutionPolicy>]
    [-Command { - | <script-block> [-args <arg-array>]
                  | <string> [<CommandParameters>] } ]


#  Command 的值為"-", 將會打印幫助文檔 同 powershell -c
powershell -c -

# Command 的值為腳本塊,只在 powershell 環境下才有效。
# 而 cmd 下會原樣輸出,且數據必須在括號中,否則報錯
powershell -c {Test $HOME}

# Command 的值為字符串,則該字符串必須是最后一個參數
# 執行字符串中的命令返回結果且輸出 test
powershell -c "echo $HOME" test   

# 運行 Windows PowerShell 命令的字符串, 不會輸出 test
powershell -c "& {$HOME}" test

# 實際發現省略 -c 命令也可以實現(暫未深入研究其原因)
powershell $HOME

結果如圖:

三、使用 PowerShell 做數字比較

1.通過上述的幫助文檔,就可以愉快的做數字比較和計算了。不過這里還是列一下 PowerShell 的比較運算符,其他還是移步官方文檔或文末鏈接地址查閱。

-eq:等於            -ne:不等於
-gt:大於             -ge:大於等於
-lt:小於             -le:小於等於
-contains:包含        -notcontains:不包含

2.再來看看數字比較和計算,可以發現很方便,既能通過判斷自定義顯示結果,也能直接顯示比較結果。

3.對於最開始的磁盤空間比較計算的問題已經可解決了,但大串的數字寫起來還是挺麻煩的,不過 PowerShell 可以識別計算機容量單位, 包括 KB,MB,GB,TB,PB。那么我們就能更加愉快的玩耍了

@echo off
for /f "tokens=1,2 delims=:" %%i in ('fsutil volume diskFree D:\ ^|findstr "可用字節總數"') do (
	@rem 計算時會進行四舍五入
	@rem 等同 powershell "'{0:N2}' -f (%%j/1GB)"
	powershell "$s='{0:0.00}' -f (%%j/1GB);$s+' GB'"
)

pause

四、調用 PowerShell 的細節及場景

1.調用本質
整體來說在使用批處理時可以通過 PowerShell 來彌補不足。究其調用本質----> 開啟一個 PowerShell 進程實現操作結束后退出。如圖所示

2.調用細節
本文中的腳本只對調用 PowerShell 的結果進行展示,那如何賦值給變量或管道輸出呢?

# 不換行結果顯示
set /p =HomePath: <nul
powershell "$HOME"

# 輸出值賦給批處理腳本變量
for /f %%i in ('powershell "1+2"') do (
	set sum=%%i
)
echo 賦值結果:%sum%

# 管道輸出給批處理的其他命令
powershell $HOST | findstr /i name

# 批處理參數傳給 PowerShell 使用
set total=100
powershell "'平均值為: '+ %total%/10"

3.其他場景

批處理運行時彈框選項【powershell 彈框

@echo off

echo After 3 seconds, the prompt box will appear...
timeout /t 3 >nul
set pscommand='powershell "$IP=ForEach($ip in (ipconfig) -like '*IPv4*'){'IP Address:'+($ip -split ' : ')[-1]};$showIp=New-Object -ComObject WScript.Shell;$showIp.popup(\"$IP\",0,'ShowIP',1+64)"'

for /f %%i in (%pscommand%) do (
	if %%i==1 ( echo You selected the OK button )
	if %%i==2 ( echo You selected the CANCEL button )
)

pause

批處理調用執行 PowerShell 腳本文件

powershell -File .\run.ps1

未完,待續...

PowerShell 博客


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM