PowerShell Quick Reference Chris Morgan – 9/10/2011 Downloading PowerShell -- http://support.microsoft.com/kb/968929 IDEs for PowerShell – ISE comes with it, PowerGUI is a free alternative Start Accessories Windows PowerShell Set properties on the console window – colors, width, height, buffer, position Setting prompt Enter “$profile” at the PowerShell prompt to see where to create the folder notepad $profile test-path $profile Test to see if the file exists In $profile, create a function like: function prompt {"PS $pwd>"} Or function Prompt { $max = 40 $str = $pwd.path if ($str.length -ge $max) { $str = "..." + $str.substring($str.length - $max + 4) } $history = @(get-history) $curr = [string]($history.count+1) $str = $str + "[$curr]" "PS $str>" $host.ui.RawUI.WindowTitle = "PS: " + $pwd } Three important rules about PowerShell scripts: 1. A PowerShell script has the extension “.ps1”. PowerShell v1.0 and v2.0 both use the same .ps1 extension. 2. To run scripts you have to explicitly enable them by setting the “execution policy”, as follows: set-executionpolicy remotesigned 3. To run scripts in the current directory just enter the script name. BUT, you have to precede it with “.\”: .\myscript.ps1 Miscellaneous tips and rules: All references to variables start with a dollar sign. It says “what follows is a variable name”. All comparison operators and parameters begin with a dash, as in: –lt -gt -eq -contains –matches You can save the output of any operation to a variable. For example: $d = dir *.txt Everything is an object in PowerShell (they all have properties and methods) Variables don’t have to be declared. They automatically get set to a type. However, you can specify the type of a variable if you want. $d = [datetime]”06/06/2011” makes the string a datetime variable type and, hence, $d is too. Other types are [int], [string], [double]. You can find out what properties and methods are defined on an object by using Get-Member, as in $d | get-member $profile | get-member Just typing the name of variable will show you the contents of it 3/17/2016 Document1 Page 1 $profile Get-help command is your friend. There is lots of built-in help. Try: get-help variables Get-help has the following 3 options: –examples -detailed –full Get-history command shows a list of recent commands h command does the same h 25 gets the 25th command out of the history h 25 –count 5 gets the 5 commands leading up to and including the 25th command. <F7> key (like in DOS) pops-up a list of commands you can scroll through. A comment line in a script begins with a pound sign - # Comment blocks are <# . . . #> ` (backtick or backquote) is used in scripts to continue a command onto the next line or in a command to “escape” a character to make it a literal, like in “`#COMMAND” to make the pound sign character a literal character instead of the beginning of a comment. Also, `t is a tab, `n is a new line, etc. for special characters. There is no way to require declaring variables in scripts. It is, however, possible to declare variables before they are used and to set the scope of the variable (local: (default), private:, script:, global:) Help Get-help (or just ‘help’ to display a page at a time) has a list of topics that all start with “about_”. To see all the topics: help about_* get-help profile|out-file profile.txt -encoding ascii|notepad profile.txt Get-Command to get a list of all the built-in commands Many normal DOS commands work in PowerShell. However, they may not work in exactly the same way or have the same options: dir md cd move copy cls ren (gc is like ‘list’) Actually, each of these commands is an alias for the real command. To find out what the real command is use get-alias: get-alias dir Or dir alias: dir alias:dir dir alias:d* to see them all to see just the alias on dir to see all commands that start with d that are an alias. To switch drives, just enter the drive letter, as in DOS. For example: c: or d: There are other “drives” in PowerShell. Try doing a dir on env:, variable:, or function: dir env: dir variable: dir function: dir hklm: dir hkcu: dir alias: There are a number of built-in variables (dir variable: to see all variables in memory) $pid Process ID of the current process $pwd Current path 3/17/2016 Document1 Page 2 $profile Full path and name of the PowerShell profile file $home home path $pshome PowerShell path $psversiontable PowerShell version info The dir command can work like you expect: Gets a list of all the txt files in the current directory dir *.txt Variations of the dir (or “Get-ChildItem”) command: dir dir dir dir dir dir *.txt|sort lastwritetime -desc | where {$_.PSIsContainer} | where {!$_.PSIsContainer} | select name, length | select {$_.name.padright(20) + " | select {$_.name.padright(20) + " Sorts by DateTime in descending order Gets just a list of directories Gets just a list of files Show only the filename and size " + $_.length} Formats the filename and size some " + $_.length.tostring().padleft(10)} More formatting It can also do something you don’t expect – take an array of patterns to search on: Dir (“*.inc”,”*.pkg”,”*.mac”) Gets all the inc, pkg, and mac files in the current directory. What is in parentheses is an array of values. Get the count of directory entries (dir).count The parentheses causes the command to execute first dir.count This won’t work If you want to see all the files in subdirectories too, there is a different syntax: dir * -include *.inc –recurse Get all the “drives” with the get-psdrive command get-PSDrive Change to a “drive” by using the CD command: cd env: cd variable: Then you can use DIR to see all the entries in that drive. The registry can be navigated by using the CD command to go to a “subdirectory” of the registry “drive”. You can also reference a “subdirectory” by using a “\”, as in: cd hklm: dir software\microsoft\office Scripts Powershell scripts are text files that have an extension .ps1. Parameters passed to a script can be accessed by referencing the built-in array It is a zero-based array. So, the first parameter passed to the script is $args[] $args[0] To run a script called Test.ps1 in powershell, enter at the command prompt: .\test parm1 parm2 If you are in the DOS command shell, enter powershell 3/17/2016 Document1 .\test first_parm second_parm Page 3 You can create a DOS batch file to run a powershell script and retrieve the exit code from the script as an errorlevel in DOS. Exit the Powershell script with a “exit 10” command. The batch file (call it ps.bat) runs the script passed on the command line (together with any parameters) and then references the last exit code from the script: @echo off powershell.exe -command “%*” ; exit $LastExitCode echo Error Code: %errorlevel% Functions Function myfunc($parm1, [int]$parm2) {command 1; command2; return $str} or Function myfunc {param($parm1, [int]$parm2); command 1; command2; return $str} Working with Environment Variables Get the path environment variable and store it in a variable Display the path with each entry on its own line Turn the environment string into an array of values. Display the 6th entry in the path string Get the number of path entries Same Adds an array element to the end Change the 16th array value to “new stuff” Changes the last element in the array to “xyz” Takes the array of elements in the $p1 array and joins them all together into a single string, with a semi-colon concatenation character in between each element. $env:newpath = $p2 Sets the ‘newpath’ environment variable to the $p2 string. foreach($e in $p1){$e} Show all the elements in the $p1 array $env:path += “;c:\dataflex\bin” Add another path to the environment path variable $p = $env:path $p.split(“;”) $p1 = $p.split(“;”) $p1[5] $p1.count $p1.length $p1 += “new entry” $p1[15] = “new stuff” $p1[($p1.count-1)] = “xyz” $p2 = $p1 -join (“;”) String Handling Now do some more stuff with string handling. Get just the array elements from $p1 where it begins with certain characters. foreach($e in $p1){if($e.tolower().startswith(“c:\prog”)){$e}} By the way, here’s a list of some useful string methods to try out (use get-help to learn more about each): Clone PadRight ToUpper CompareTo Remove Trim Contains Replace TrimEnd CopyTo Split TrimStart EndsWith StartsWith Equals Substring GetType ToCharArray Insert ToLower PadLeft ToString File search tutorial dir *.txt $txt = dir *.txt $txt.count $txt | get-member foreach ($f in $txt) {$f} foreach ($f in $txt){$f.name} $txt | select name $txt | select –first 5 | select directory, name $txt | select –last 5 | select directory, name 3/17/2016 Document1 Page 4 dir * -include *.txt –exclude *.flx –recurse dir * -include *.txt,*.inc,*.pkg –exclude *.flx –recurse dir dir dir dir |where |where |where |where {$_.PSIsContainer} {!($_.PSIsContainer)} {$_.length –gt 10000} {$_.lastwritetime –gt “1/1/2008”} show only the directories show all but the directories show files that are 10k or larger show files with a date after 1/1/2008 dir –r |select name recurse all subdirectories dir -i *.txt –r | select-string “policy” dir -i *.html -r | select-string "Virtual University"| select {($_.linenumber.tostring().padright(5) + " " + $_.line.padright(60).substring(0,60))} foreach ($f in get-childitem -include *.html -r){$f.name} foreach ($f in get-childitem -include *.html -r) {if ($f.creationtime –lt $(get-date).addmonths(-50)){$f.name}} Double search. This next example looks at all PKG files and gets a list of those that have “procedure entering” in them. Then it does a second search, but just on this list of files, for those that contain “refresh”: dir *.pkg|select-string "procedure entering"|select filename -unique| foreach {dir $_.filename}|select-string "refresh" dir *.pkg|select-string "procedure entering"|select filename -unique| foreach {dir $_.filename}|select-string "refresh"|select filename -unique This line looks at three types of files: PKG, INC, & MAC: dir ("*.pkg","*.inc","*.mac")|select-string "procedure"|select filename -unique| foreach {dir $_.filename}|select-string "refresh"|select filename –unique Files get-content file.txt Get the contents of file.txt, splitting the file into lines gc file.txt Same gc fmac –delimiter `#DELIMITER Get contents of FMAC, but split file at #ENDCOMMAND; not by lines out-file file.txt –encoding ascii –append set-content file.txt “Here is some text” add-content –path file.content –value “here is some text” clear-content file.txt (Test-Path file.txt) Test to see if ‘file.txt’ exists. > file.txt redirect output to a file >> file.txt redirect that appends output to a file $fn = [System.IO.Path]::GetTempFileName() Create a temporary file. We can use it to store info to. dir *.txt|foreach {move-item $_.fullname .\test} Move all the TXT files from the current dir to subdir “Test” Some misc examples: $errlog $errlog $errlog $errlog $errlog $errlog foreach = get-content c:\windows\temp\errlog.txt = get-content c:\windows\temp\errlog.txt| measure-object = get-content c:\windows\temp\errlog.txt -last 10 = get-content c:\windows\temp\errlog.txt -totalcount 100 = get-content c:\windows\temp\errlog.txt -skip 1 = get-content c:\windows\temp\errlog.txt| out-file -encoding ASCII c:\logs\errlog.txt ($line in $errlog) {if($line.contains("getting")){"Found: " + $line.substring(1,17) }} $errlog| where {$_.contains("getting")} |out-file -encoding ASCII c:\logs\errlog1.txt 3/17/2016 Document1 Page 5 Rename file extension Dir *.txt | rename-item –newname {$_.name.replace(‘.txt’,’.csv’)} Get a list of all the file types in the current directory and create a directory for each unique type, but not "INC": dir |select-object extension |sort-object extension -unique |where {$_.extension -ne ".INC" |foreach {if (($_.extension -ne "") -and !(test-path $_.extension.substring(1,3))) { new-item $_.extension.substring(1,3).ToUpper() -type directory }} When broken into a 2-step process, this works too: $a = get-childitem | select-object extension | sort-object extension -unique foreach ($dir in $a) {if (($dir.extension -ne "") -and !(test-path $dir.extension.substring(1,3))) {new-item $dir.extension.substring(1,3).ToUpper() -type directory }} write-host "The number of file types is: " $a.count Move all TXT and PS1 files to their respective subdirectories dir ("*.txt","*.ps1")|foreach {$ext = (".\" + $_.extension.substring(1,3)); move-item $_.fullname $ext } Date handling $now = get-date $now | get-member to see the methods and properties you have access to $somedate = [DateTime]”01/01/2011” $now.year .month .day .timeofday $now.timeofday.hours .minutes $now.timeofday.hours.tostring() $diff = $now - $somedate $diff.totaldays $diff is a “TimeSpan” data type, whereas $now is a “DateTime”. Arrays $a = 1,2,3,4,5,6,7,8,9,10 $a = 1..10 $min = 10 $max = 18 $a = $min..$max $a[0] first element $a.count number of elements $b = 20, 21, 22, 23, 24 $c = $a + $b results is 1,2,3,4,5,6,7,8,9,10,20,21,22,23,24,25 Note: See “Working with Environment Variables” above for more on arrays Sorting and Grouping $dir = “x:\proj\release” $phrase = “log” $f = get-childitem $dir –r –exclude *.zip $f | select-string $phrase | group-object filename | sort-object count -desc gc log.txt | group gc log.txt | sort gc log.txt | sort –unique gc log.txt | foreach{$_.trim()} | sort Remove all the leading spaces on each line before sorting dir | select extension | sort extension –unique dir | select extension | group extension | sort count -desc Get the contents of the set.pkg, trim all the leading spaces, then group all the lines that are alike and sort the result by number of times each similar line is found in the file and, finally, display the duplicate count and the text of the line. 3/17/2016 Document1 Page 6 gc set.pkg|foreach{$_.trim()}|group|sort count|foreach {$_.count.tostring() + " " +$_.name} For and Foreach $f = get-content logfile.txt Get the contents of a text file and move to an array variable $count = $f.length for ([int]$i=0 ; $i –lt $count ; $i++) { if ($f[$i].contains(“some text”)){ $f[$i] } } foreach ($line in $f){ if ($line.contains(“some text”)){$line}} or get-content logfile.txt| where {$_.contains(“some test”)} Processes and Jobs start-process notepad Or $proc = [diagnostics.process]::start("notepad.exe", "$pwd\file.txt") $proc.close() Or $id = $proc.id stop_process $id start-sleep –seconds 15 start-process powershell.exe start-job stop-job wait-job receive-job get-job To start up another PowerShell command shell Start a job in the background while you continue to work Stop a job you started Wait until a designated job completes Get the return result from a running or just completed job Get a list of current running jobs CSV and XML files import-csv ConvertFrom-csv export-csv ConvertTo-csv –delimiter “;” User Interaction Write-Host “There are $c files in this directory.” //where $c=(dir *.txt).count write-host –nonewline “Press any key to continue...” write-output “Press any key to continue...” $key = $host.ui.rawui.readkey(“NoEcho, IncludeKeyDown”) $input = Read-Host “Enter some text here” write-host -f white -b red "This is some text" Display white text on a red background get-content newfile.txt|foreach {if ($_.contains('second')){write-host -f white -b red $_} else {write $_} } Show selected lines as white on red; the others in normal colors dir *.txt| out-gridview Word, Excel, and Internet Explorer $excel = new-object –comobject (“excel.application”) or $excel = new-object –comobject excel.application $wb = $excel.workbooks.add() 3/17/2016 Document1 Page 7 $ws = $wb.worksheets(1) $excel.visible = $true $wb.activesheet.cells.item(5,1) = “Hello World” $ws.cells.item(5,2) = “Another World” $cell = $wb.activesheet.cells.item(5,1).text or $cell = $ws.cells.item(5,2).text $wb.saveas(“mysheet.xlsx”) $wb.saveas(“mysheet.csv”,6) Or, to save as a CSV file. $wb.close() $excel.quit() Option to not display alerts in Excel: $excel.displayalerts = $false $wb = $excel.workbooks.open(“mysheet.xlsx”) $wb.opentext() $word = new-object –comobject word.application (more to come here) $ie = new-object –comobject InternetExplorer.application $ie.visible = $true $ie.navigate(http://ingenix.com/login/) $ie.readystate $ie.quit() if ($ie.readystate –eq $null){write-host “IE has been closed”} if ($ie.readystate –eq 4){write-host “Last request finished”} Computer Access Get a list of cookies on the current computer, sorted by date: $a = new-object –comobject shell.application $cookies = dir $a.namespace(0x21).self.path | sort lastwritetime –descending foreach ($cookie in $cookies){$cookie.name} Or, to get a list of what items are on the desktop, replace “0x21” with “0x0” in line 2. SQL Server $sql = new-object system.data.sqlclient.sqlconnection(“Server=HP8430\SQLEXPRESS; Trusted_Connection=Yes; Database=Northwind”) $sql.open() $cmd = $sql.createcommand() $cmd.commandtext = “select * from customers” $results = $cmd.ExecuteReader() while ($results.read()){write-host $results.item(“CompanyName”) “ “ $results.item(“City”)} $sql.close() $cmd.commandtext = “create table MyTable(ID int, Name varchar(50), Addr varchar(50), BDay datetime)” $result = $cmd.ExecuteNonQuery() $cmd.commandtext = “select count(*) from Customers” $result = $cmd.ExecuteScalar() Windows Form [void][reflection.assembly]::LoadWithPartialName(“System.Windows.Forms”) $form = new-object Windows.Forms.Form $button = new-object Windows.Forms.Button $button.text = “Press here” $button.dock = “fill” $button.add_click({form.close()}) $form.controls.add($button) $form.add_shown({$form.activate()}) $form.showdialog() 3/17/2016 Document1 Page 8