Windows/Scripting

From Segfault
Jump to navigation Jump to search

PowerShell

Check version and update as needed:

PS C:\Users\bob> $PSVersionTable
PSVersion                      5.1.22000.2003
PSEdition                      Desktop

After PowerShell is started, find out where our profile[1] is stored, as this varies[2] between Windows versions:

% powershell
PS C:\temp> $profile
C:\Users\bob\Documents\WindowsPowerShell\Microsoft.PowerShell_profile.ps1

We can now create scripts in Microsoft.PowerShell_profile.ps1 that will get loaded the next time PowerShell starts. E.g., setting a prompt[3] or defining functions:[4]

function prompt
{
   "PS " + $(get-location) + "> "
}

function sudo {
   Start-Process @args -verb runas
}

Before we can use that script, we need to alter our execution policy for PowerShell scripts:

$ Get-ExecutionPolicy
RemoteSigned

$ Set-ExecutionPolicy RemoteSigned

With that, the locally stored Microsoft.PowerShell_profile.ps1 will now be used. Reload on the fly via . $PROFILE.

Core commands

Let's grep for strings:

$ gci env: | findstr "^OS"
OS                             Windows_NT

Use tail to follow a file:

Get-Content file.log -Wait
Get-Content file.log -Wait -Tail 10             # print the last 10 lines, then follow (PowerShell 3 only)

Search for something while running tail:

Get-Content file.log -wait | where { $_ -match "foo" }

Use head in combination with sort:

$ gci env:* | Select -first 3 | Sort-Object name
LOGONSERVER                    \\example
USERNAME                       bob
USERPROFILE                    C:\Users\bob

A very simple netcat substitute, for UDP and TCP:

(New-Object Net.Sockets.UdpClient).Connect("some-host",1234)
(New-Object Net.Sockets.TcpClient).Connect("some-host",1234)

rename

Based on an overcomplicated workflow, we had the following problem to solve: rename PDF files based on their file content. In lieu of awk,[5][6] we used a few lines of PowerShell (courtesy of someone else) and pdftotext.exe and arrived at the following:

$confirmation = Read-Host "Press Y to proceed, any other key to cancel!"
if ($confirmation -eq 'y') {
    $files = Get-ChildItem "*.pdf"
    
    foreach ($f in $files){ $newname = 
        ( .\pdftotext.exe $f - | 
        findstr "For:" | 
        %{ $_.Split(' ')[-1];} |
        %{ $_.Split('[()]')[1];} )
    
    $newname = $newname + ".pdf"
    "$f => $newname"
    Rename-Item $f $newname
    }
    pause
}

The Windows installation did not allow[7] to execute the .ps1 file with a double-click, so we needed a small wrapper script (.bat) to help here:

powershell -ExecutionPolicy ByPass -File pdf_rename.ps1

Playing sounds

This even works from a plain command line:[8]

powershell -c (New-Object Media.SoundPlayer 'c:\users\dummy\test.wav').PlaySync();

Battery status

Via wmic:WMIC: WMI command-line utility</ref>

$ wmic path Win32_Battery get EstimatedChargeRemaining
EstimatedChargeRemaining  
68

The powercfg[9] command creates a nice HTML report:

powercfg /batteryreport

CMD

while loop

@echo off
setlocal enableextensions enabledelayedexpansion
set /a "x = 0"
:while1
    if %x% leq 5 (
        echo %x%
        set /a "x = x + 1"
        goto :while1
    )
endlocal

for loop

for /l %a in (1, 1, 100) do echo %a

Or, when operating on files:

for /f %a in ('dir /b /d') do move %a dir\%a

Move all files in all subdirectories into one single directory:

mkdir single_dir
cd subdir_structure
for /r %d in (*) do move "%d" ..\single_dir

forfiles

There's also forfiles available for Windows Vista and later versions (or via the Windows Resource Kit[10]), that can do things like delete files older than N days[11]:

forfiles /p "c:\what\ever" /s /m *.* /d <number of days> /c "cmd /c del @path"

To expand on that, find recent files greater than 200 MB:[12][13]

$ forfiles /p c:\    /s /d +"11/01/2023" /c "cmd /c if @fsize gtr 209715200 echo @path @fsize @fdate @ftime"
"C:\pagefile.sys"                                                1073741824 11/2/2023 5:03:32 PM
"C:\Users\root\AppData\Local\VirtualStore\Windows\DataStore.edb"  604045312 11/2/2023 5:11:51 PM
"C:\Windows\SoftwareDistribution\DataStore\DataStore.edb"         604045312 11/2/2023 5:19:22 PM
"C:\Windows\winsxs\ManifestCache\702349c5b78f9a04_blobs.bin"      211158729 11/2/2023 5:44:16 PM

/dev/null

echo "hello" > NUL

date/time

$ echo %date%%time%
27.07.2011 4:44:21,50

tee

This really just redirects stdout to a file and then[14] displays it:

dir > a.txt && type a.txt

wmic

Gather version information with wmic[15]:

$ wmic datafile where name='c:\\Program Files\\7-Zip\\7z.exe' get version
Version
9.20.0.0
  • The double backslashes are important.
  • Only single quotes will work, double quotes will produce an error.

Gather installed software packages:[16]

$ wmic softwarefeature get productname,version | find /i "zip"
7-Zip 9.34                      9.34.00.0

Links

References