Self-Elevating PowerShell and Batch Scripts

Many scripts require admin permissions, but remembering to right click and select “Run as Administrator” can be a pain. Fortunately, both batch and PowerShell scripts can written so that they’ll prompt for admin permissions if not run as an administrator. This won’t get around not having administrator permissions, but will save you a couple clicks every run by jumping straight to the UAC prompt.

Neither of these scripts are mine, but I’m documenting them here for my own quick and frequent reference.

CMD / Batch scripts:

::::::::::::::::::::::::::::::::::::::::::::
:: Elevate.cmd - Version 4
:: Automatically check & get admin rights
:: see "https://stackoverflow.com/a/12264592/1016343" for description
::::::::::::::::::::::::::::::::::::::::::::
 @echo off
 CLS
 ECHO.
 ECHO =============================
 ECHO Running Admin shell
 ECHO =============================

:init
 setlocal DisableDelayedExpansion
 set cmdInvoke=1
 set winSysFolder=System32
 set "batchPath=%~0"
 for %%k in (%0) do set batchName=%%~nk
 set "vbsGetPrivileges=%temp%\OEgetPriv_%batchName%.vbs"
 setlocal EnableDelayedExpansion

:checkPrivileges
  NET FILE 1>NUL 2>NUL
  if '%errorlevel%' == '0' ( goto gotPrivileges ) else ( goto getPrivileges )

:getPrivileges
  if '%1'=='ELEV' (echo ELEV & shift /1 & goto gotPrivileges)
  ECHO.
  ECHO **************************************
  ECHO Invoking UAC for Privilege Escalation
  ECHO **************************************

  ECHO Set UAC = CreateObject^("Shell.Application"^) > "%vbsGetPrivileges%"
  ECHO args = "ELEV " >> "%vbsGetPrivileges%"
  ECHO For Each strArg in WScript.Arguments >> "%vbsGetPrivileges%"
  ECHO args = args ^& strArg ^& " "  >> "%vbsGetPrivileges%"
  ECHO Next >> "%vbsGetPrivileges%"

  if '%cmdInvoke%'=='1' goto InvokeCmd 

  ECHO UAC.ShellExecute "!batchPath!", args, "", "runas", 1 >> "%vbsGetPrivileges%"
  goto ExecElevation

:InvokeCmd
  ECHO args = "/c """ + "!batchPath!" + """ " + args >> "%vbsGetPrivileges%"
  ECHO UAC.ShellExecute "%SystemRoot%\%winSysFolder%\cmd.exe", args, "", "runas", 1 >> "%vbsGetPrivileges%"

:ExecElevation
 "%SystemRoot%\%winSysFolder%\WScript.exe" "%vbsGetPrivileges%" %*
 exit /B

:gotPrivileges
 setlocal & cd /d %~dp0
 if '%1'=='ELEV' (del "%vbsGetPrivileges%" 1>nul 2>nul  &  shift /1)

 ::::::::::::::::::::::::::::
 ::START
 ::::::::::::::::::::::::::::
 REM Run shell as admin (example) - put here code as you like
 ECHO %batchName% Arguments: P1=%1 P2=%2 P3=%3 P4=%4 P5=%5 P6=%6 P7=%7 P8=%8 P9=%9
 REM put remaining commands here
 cmd /k

source (stackoverflow)

PowerShell:

Fortunately this one’s a lot shorter:

If (-NOT ([Security.Principal.WindowsPrincipal][Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole] "Administrator"))

{   
	$arguments = "& '" + $myinvocation.mycommand.definition + "'"
	Start-Process powershell -Verb runAs -ArgumentList $arguments
	Break
}

source (stackoverflow)

PowerShell: Ping Range of IP Addresses

The other day I needed to scan a small section of our network which uses static IP addresses rather than DHCP to see which assigned IP addresses actually correlated with a working device and which were no longer being used by an active device. Though there are plenty of fancy tools for this, due to the simplicity of what I wanted I figured it would be easier to throw together a quick PowerShell script than install and learn a third-party tool.

Here’s what I came up with:

$Failure = @() #initialize array

#pings IP addresses from 192.168.1.0 to 192.168.1.255
for ($i=0; $i -le 255; $i++)
{
	$IP = "192.168.1." + $i #append the iterator as the last byte of the IP address
	if(!(Test-Connection -ComputerName $IP -Quiet -Count 2)){ #if noting responds to the ping, add the IP address to an array
        $Failure += $IP
	}
}

Clear-Host

foreach ($site in $Failure) {
    Write-Host $site -ForegroundColor red #iterate through and write results from array
}

Note that this runs really slowly, but in this case there wasn’t any rush, so I could let it run in the background for a while.

Domain User Account Info

This is a short but incredibly useful command line command I’ve found for pulling information on domain accounts in an Active Directory environment:

net user [username] /domain

The net user command is designed to create / update domain accounts, but in this form just displays a ton of info that can be useful to IT, like when a user’s password expires, what active directory groups they’re a member of, etc. There’s plenty of other commands to do similar things, but this one is an easy way to get a readout of a ton of information.

Full documentation is available on Microsoft’s website.

PowerShell: Starting Remote Desktop Once Server Available

This is a simple but useful bit of PowerShell. Have you ever been waiting on a server to reboot and ended up pinging it or trying to start a remote desktop session several times before it’s back up and you can log in? This script pings a server (or any computer) every 15 seconds until the server responds, then starts a remote desktop session.

param ([Parameter(Mandatory=$true)][string]$URL)#get the parameter and set it as the variable $URL

While (!(Test-Connection -ComputerName $URL -Quiet -Count 1)) { #Loops until Test-Connection reaches the server and returns true. Only tries one ping at a time
	Start-Sleep -s 15 #pauses for 15 seconds. Easily editable to different time lengths
}

mstsc /v:$URL #starts a remote desktop session

To use it, just save and run the script, passing the hostname or IP address as a parameter:

PowerShell screenshot showing passing an IP address as a parameter.

And if you want it as a one-liner you can copy and paste rather than saving it, use the following and replace the IP address at the beginning with the target IP address or hostname:

$URL = "192.168.0.3"; While (!(Test-Connection -ComputerName $URL -Quiet -Count 1)) { Start-Sleep -s 15 } ; mstsc /v:$URL