User Tools

Site Tools


aoe:powershell

list inactive users

List all inactive users

Search-ADAccount -AccountInactive | where {$_.ObjectClass -eq 'user'} | Format-Table -wrap -A Name,SamAccountName,LastLogonDate | Out-File Z:\sandbox\inactiveusers.txt -Encoding ascii 

List all inactive users older than 1 year

Search-ADAccount -AccountInactive -TimeSpan | where {$_.ObjectClass -eq 'user'} | Format-Table -wrap -A Name,SamAccountName,LastLogonDate | Out-File Z:\sandbox\inactiveusers.txt -Encoding ascii 

Apply remote allowed settings to Advanced Firewall Rules to license4.aoe.vt.edu

set-executionpolicy unrestricted (bad, use remote signed instead)
 $List1 = @("128.173.188.0/16","198.82.0.0/16","172.16.0.0/12","2001:468:c80::/48","2607:b400::/40","2002:80ad::/32","2002:c652::/32")
 $List2 = @("192.168.50.0/24")

#STK License Server Daemon UDP

 Set-NetFirewallRule -DisplayName "STK License Server Daemon UDP" -RemoteAddress $List1
 Set-NetFirewallRule -DisplayName "STK License Server Daemon TCP" -RemoteAddress $List1
 Set-NetFirewallRule -DisplayName "STK License Manager vendor daemon UDP" -RemoteAddress $List1
 Set-NetFirewallRule -DisplayName "STK License Manager vendor daemon TCP" -RemoteAddress $List1

 Set-NetFirewallRule -DisplayName "PHX License Server Daemon UDP" -RemoteAddress $List1
 Set-NetFirewallRule -DisplayName "PHX License Server Daemon TCP" -RemoteAddress $List1
 Set-NetFirewallRule -DisplayName "PHX License Manager vendor daemon UDP" -RemoteAddress $List1
 Set-NetFirewallRule -DisplayName "PHX License Manager vendor daemon TCP" -RemoteAddress $List1

 Set-NetFirewallRule -DisplayName "Mathcad License Server Daemon UDP" -RemoteAddress $List1
 Set-NetFirewallRule -DisplayName "Mathcad License Server Daemon TCP" -RemoteAddress $List1
 Set-NetFirewallRule -DisplayName "Mathcad License Manager vendor daemon UDP" -RemoteAddress $List1
 Set-NetFirewallRule -DisplayName "Mathcad License Manager vendor daemon TCP" -RemoteAddress $List1

 Set-NetFirewallRule -DisplayName "Intel FlexNet Publisher* License Server Daemon UDP" -RemoteAddress $List1
 Set-NetFirewallRule -DisplayName "Intel FlexNet Publisher* License Server Daemon TCP" -RemoteAddress $List1
 Set-NetFirewallRule -DisplayName "Intel(R) Software* License Manager vendor daemon UDP" -RemoteAddress $List1
 Set-NetFirewallRule -DisplayName "Intel(R) Software* License Manager vendor daemon TCP" -RemoteAddress $List1

Random notes including stuff from Lynda.com PowerShell 5 Essential Training

netsh is the older command that works on windows 7 and might get dropped in future releases.

netsh interface ipv6 6to4 set state disabled
netsh interface teredo set state disabled
netsh interface ipv6 isatap set state disabled

Windows 8.1 and up can use Get-NetAdapter which is a little easier to work with:

Get-DnsClientServerAddress 
Get-NetAdapter | SELECT name, status, speed, fullduplex | where status -eq ‘up’
Get-NetIPConfiguration | select InterfaceAlias, IPv4Address | where InterfaceAlias -eq 'Ethernet' (replace with result from above.)
Get-NetAdapter | where status -eq 'up' | Get-NetIPAddress -ea 0 | where AddressFamily -eq 'IPv4' | select IPAddress | Where {$_.IPAddress -like "128.173.*" -OR $_.IPAddress -like "198.82.*"}

The -ea is an error action switch. Zero means continue silently. Might not be needed.

if the address begins with 128.173 or 198.82, then set these DNS settings:

netsh interface ip set dns “Local Area Connection” static 128.173.188.25
netsh interface ip set dns “Local Area Connection” static 128.173.188.26
netsh interface ipv6 set dns “Local Area Connection” static 2001:468:c80:610c:ccfb:66e9:490f:d18
netsh interface ipv6 set dns “Local Area Connection” static 2001:468:c80:610c:d1cd:8142:30a:3a7a

Save Configuration:

netsh interface dump > mycfg.dat

Restore Configuration:

netsh exec mycfg.dat

Works with ps3:

Get-WmiObject win32_networkadapterconfiguration IPEnabled,DNSServerSearchOrder -Filter IPEnabled=True IPAddress
Get-WmiObject win32_networkadapterconfiguration IPEnabled,DNSServerSearchOrder,IPAddress | ? {$_.IPEnabled=True}
$adapter = Get-WmiObject win32_networkadapter -Filter ‘index = 13’
$adapter.NetConnectionID
Get-WmiObject -Class Win32_NetworkAdapter | Get-Member
Get-WmiObject -Class Win32_NetworkAdapter -Filter NetEnabled=TRUE NetConnectionID

Lynda.com Powershell training notes:

Get-ChildItem is dir or ls and has an alias of gci.

get-service -name "*net*"
get-service | out-file c:\services.txt
get-command
get-help get-childitem
get-help has an alias of gh
get-service | where-object {$_.status -eq "stopped"}
get-service | get-memeber

Create a function:

function add <then hit enter>
>>> {
>>> $add =[int](2+2)
>>> write-output "$add"
>>> }
add

-whatif tells what would happen if the command runs

-confirm allows the operation on each object to get a y/n/etc prompt

ise (brings up Integrated Scripting Environment)
get-service | format-list displayname, status, requiredservices
get-service | format-table displayname, status required
get-service | sort-object -property status | format-list
get-service | sort-object -property status | format-list displayname, status, requiredservices
get-service | outfile c:\services.txt
get-service | export-csv c:\services.csv

in the ISE, highlight highlighted text can be run individually

Grid View

get-service | out-gridview
get-service | select-object displayname, status, requiredservices | out-gridview 
get-service | select-object * | out-gridview 

Modules

get-module -listavailable
import-module -name applocker
get-command -module applocker

Module creation

Save script as .psm1

Import-Module ./Diskinfo.psm1 -force -verbose
cat Env:\PSModulePath

Put file in the User location returned. The location will need to be created.

$env:PSModulePath

or separated

$env:PSModulePath -split ";"

C:\Users\stedwar1\Documents\WindowsPowerShell\Modules
C:\Windows\system32\WindowsPowerShell\v1.0\Modules\

Use only the user area to put modules

get-help *diskinfo* #Listed as a function

execution policy

get-executionpolicy
set-executionpolicy restricted #default setting

Set the following to execute:

Set-ExecutionPolicy RemoteSigned
Set-ExecutionPolicy Restricted
powershell -ExecutionPolicy ByPass -File script.ps1

Signing

Set-AuthenticodeSignature .\diskinfo.ps1 $cert -TimestampServer http://timestamp.comodoca.com/authenticode
Get-AuthenticodeSignature .diskinfo.ps1 | format-list
dir cert:\CurrentUser -Recurse -CodeSigningCert -OutVariable a
$a
$cert = $a[0]

Test.ps1

write-Output "Hello world"
set-executionpolicy allsigned

Now the code will not run

set-authenticodesignature -certificate $cert -filepath ./Test.ps1
cat ./Test.ps1 # will now have a big signature appended to the file
get-help about_signed

Windows feature

get-windowsfeature
get-windowsfeature -name web-server
get-windowsfeature -name web-server | install-windowsfea...

Example scripts

Aliases

To see the aliases:

get-alias

To see what an alias does:get-alias ls

get-alias dir
get-alias cls

Update Help

First update help, and do it often

update-help -force

Basic commands

get-verb

help

get-help *array*
get-help about*
get-process
get-help get-process
get-help get-process -detailed
get-help get-process -examples
get-help get-process -full (same as detailed with additional usage information)
get-help get-process -showwindow
get-help get-process -detailed
get-help get-process -online

get-verb

extensions

get-pssnapin
get-module -ListAvailable
get-command -Module activedirectory
find-module
install-module psreadline
import-module psreadline (needs script execution: set-executionpolicy remotesigned)
find-package

Command examples

get-childitem -Path c:\ -filter *.txt*
get-help *content* (also cat and type are aliases for get-content)
get-content -path c:\filename.txt
get-eventlog -list
get-eventlog -logname security -entrytype error -newest 5

Export to XML

Compare process states

get-process | export-clixml -path c:\gold.xml
import-clixml c:\gold.xml
calc; notepad; mspaint
compare-object -referenceobject (import-clixml c:\gold.xml) -differenceobject (get-process) -property processname

Export to HTML

get-eventlog -logname system -newest 2 -entrytype error | convertto-html -title "Windows Errors" -body (get-date) -precontent "<p>Generated by IT</p>" -postcontent "For more details check the full server log" | out-file 
\\webserver\c$\c:\error.html
./error.html

Get-Member

get-service | get-member
get-service | gm
get-process | gm

From Get-Member information, we can derive these:

get-service -name bits | select-object -property name,status,machinename | format-table -autosize
get-service -name bits -computername dc,s1, client| select-object -property name,status,machinename | format-table -autosize
get-service | select-object  -Property name, status | sort-object -Property status -descending
changing column heading names
get-service -name bits | select-object -property name, @{name="ServiceName";expression={"hello"}}
get-service -name bits | select-object -property name, @{name="ServiceName";expression={$_.name}}
get-service -name bits | select-object -property @{name="ServiceName";expression={$_.name}}, status
get-service -name bits | select-object -property @{n="ServiceName";e={$_.name}}, status
get-wmiobject -class wind32_logicaldisk -filter "DeviceID='c:' " | select-object -property DeviceID, 
@{n="FreeGB";e={$_.Freespace / 1gb  -as [int] }}

Script file with parameter

<#
.Synopsys
This is the short explanation
.Description
This is the long explanation
.Parameter ComputerName
The remote computers to run the command on
.Example
DiskInfo -computername remote
This is a remote computer
.Example
DiskInfo remote
#>

function Get-diskinfo{
    [CmdletBinding()]
    param(
        [parameter(Mandatory=$True)]
        [sting[]]$ComputerName

        $bogus='localhost'
    )

    get-wmiObject -computername $ComputerName -class wind32_logicaldisk -filter "DeviceID='c:' "
}

Source the function

. ./Diskinfo.ps1

To make the function stick around

Now the function is accessible to the command line:

Get-diskinfo -Computername dc -OutVariable a
$a

Works with tab complete and get-help.

Code Formating

Line breaks can occur at commas, pipes and a few other places

selecting

get-service | where-object -filterscript {}

basic comparison

case insensitive

"Hello" -eq "hello"
true

case sensitive

"Hello" -ceq "hello"
False
"Hello" -ceq "Hello"
True
get-service | where-object {$_.status -eq "Stopped" -and $_.name -like "b*" }

more effecient to filter further left:

get-service -name b* | where-object { $_.
get-wmiobject -filter
... | where-object -filterscript {}
... | where-object {}

GPO settings

GPO: Policies, Administrative Templates, Windows Components, Windows PowerShell

Variables

get-eventlog -logname system -newest 5 -entrytype error
# variable as an object
$var=get-service -name bits
$var.status
$var.name
$var.start
$var.status #(still references initially saved state)
$var.refresh() #(updates the variable reference)
$var.status
get-help *variable*
get-variable
# variable as string
$var="hello!"
write-output $var
$var
# variable as an array
$var=1,2,3,4
$var
1
2
3
4
$var[1]
2
$var[1]=9
$var
1
9
3
4
$var[-1] #(last one in array)
$var=read-host "Enter a computerName"
$var

Automatic help generation

<#
.Synopsis
Lynda.com example
.Description
Disk Information 
.Parameter ComputeName
This is the name of a remote computer
.Example
diskinfo -computername localhost
.Example
diskinfo -computername DC
#>
param(
    [parameter(Mandatory=$true)]
    [string[]]$computername='DC',
    $NotForUse
)

# Main Code here
Get-CimInstance -computername $computername -ClassName win32_logicaldisk -filter "deviceID='c:'" |
   Select-Object -Property @{n="ComputerName";e={$_.PSComputername}},
      @{n="FreeGB";e={$_.Freespace /1gb -as [int]}}

snippets

Use control-j to bring up a list of snippets. Also found under Edit > Start snippets.

Remote Administration

get-service -computername DC #refers to the old DCOM communications method
Enable-PSRemoting
Enter-PSSession -ComputerName dc
Invoke-Command -ComputerName dc,s3,s4 -ScriptBlock {Get-service -name bits} | outfile c:\service.txt

Once the session ends, the shell is closed.

To keep the session open:

$sessions=New-PSSession -computerName s3,s4
Invoke-Command -Session $sessions {$var=2}
Invoke-Command -Session $sessions {write-output $var} #this would not be possible without the session.
Get-pssession

measure-command {icm -Computername dc {get-process}}
measure-command {icm $sessions {get-process}}

get-windowsfeature #lists all installed components
$servers='s3','s4'
$servers | foreach-object {start iexplore http://$_} #checks to see if webserver is running on each server
$sessions=New-PSSession -computername $servers
invoke-command -session $sessions {install-windowsfeature web-server}
$servers | foreach-object {copy-item ./default.htm -destination \\$_\c$\inetpub\wwwroot}

On a minimal server, the gui can be installed thus:

get-windowsfeature *gui* | install windowsfeature

Active directory tools can be used from the DC without installing RSAT on the local machine.

get-adcomputer -filter * #fails unless RSAT is installed
get-module -listavailable #show active directory is not installed
$adsession=new-pssession -computername dc
import-pssession -session $adsession -Module ActiveDirectory #imports links to the commands

This will link to the modules remotely (implicit remoting)

get-adcomputer -filter * #will now work

To get specifice pieces:

Import-pssession -session $adsession -Module ActiveDirectory -Prefix remote

A profile can be created that will set up the links each session

$profile #shows existing profile location
new-item $profile -itemtype file -force #force will overwrite if it already exists
ise $profile

Add the lines (same as above)

$adsession=new-pssession -computername dc
import-pssession -session $adsession -Module ActiveDirectory

or to put something in the name of the commands

Import-pssession -session $adsession -Module ActiveDirectory -Prefix remote
get-help *remote*
get-remoteADcomputer -filter *
get-help get-process
get-command get-process
$c=get-command get-process
$c.Parameters
$c.Parameters["Name"]

The above are functions that point to the machine where the commands run

get-command get-*ADcomputer #retuns a cmdlet and function
(get-command get-remoteAdcomputer).definition
(get-command ./GetAOE-DNS.ps1).scriptblock

$s = nsn
Import-PSSession $s -CommandName get-process -Prefix wow
get-wowprocess
invoke-command -ComputerName dc,s1,s2 {get-eventlog -Logname System -new 3} | sort timewritten | formtat-table -Property timewritten, message -Autosize
icm dc,s1,s2 {get-volume} | sort Sizeremaining | select -Last 3

invoke command comparison

Let's Powershell handle concurrency control - creates three lists: Todo, in-progress, Done. A sliding buffer. This is preferable because the second one will wait on a stalled server before proceeding.

invoke-command -ComputerName (get-content servers.txt) { }

Serially loops through the list of servers and issues the Invoke-Command

foreach ($s in (Get-Content servert.txt) ) { Invoke-Command -ComputerName $s {}}

remote powershell through a web browser

On server:

enter-PSSession <computer name>
get-windowsfeature
install-windowsfeature windowspowershellwebaccess
get-help *pswa*
install-pswawebapplication -usetestcertificate
add-pswaauthorizationrule * * * #DO NOT DO THIS ON A REAL SERVER. use get-help and set the groups properly.

More Information

Books:

Learn Windows PowerShell in a Month of Lunches

Learn PowerShell Toolmaking in a Month of Lunches

Free ebooks: https://powershell.org/ebooks/

microsoftvirtualacademy.com

Jeffrey Snover is the inventory of PowerShell “getting started with Microsoft PowerShell”

MSVA Getting Started with Microsoft Powershell v3.0

Casting XML to an object variable

$x = [xml](cat ./r_and_j.xml)
$x
$x.gettype
$x.PLAY.Act[0].SCENE[0].SPEECH
$x.PLAY.Act.SCENE.SPEECH
$x.PLAY.Act.SCENE.SPEECH | select -First 1
$x.PLAY.Act.SCENE.SPEECH | group speaker | sort count

History

get-history

Where-Object

Where-object v2 method

get-service | where-object -FilterScript {$_.status -eq "Running"}
get-service | where {$_.status -eq "Running"}
get-help *comparison*
get-help *operators*

Where-object v3 method

get-service | where {$PSItem.status -eq "Running" }

mixed

get-service | where {$PSItem.status -eq "Running" -and $_.name -like "b*" }

Simplified version

get-service | where handles -ge 1000

Advanced Piping

Sending pipe needs to have a receiving equivalent—By-Value (TypeName) first then By-PropertyName

get-member shows TypeName: at the top of the results.

The types should match

get-service | stop-process

don't match but it will fall back to byName

get-service | gm

is type ServiceController

get-help stop-process

has (-showwindow and search for byvalue)(or search for

  1. InputObject <Process[]>

that accepts pipeline input byValue as Process

get-help
get-service | stop-process -whatif

will not find the By-Value that matches ServiceController but it will find name

calc
get-process calc

get-process has a path and dir takes a path:

get-process calc | dir

Another example with an AD controller

get-adcomputer -filter * | get-service -name bits

This works, but the columns are meaninless

get-service -name bits  | select -Propery naem, stitus

Hash table syntax

get-service -name bits  | select -Propery name, @{name='ComputerName';expression={$_.name}}
get-service -name bits  | select -Propery name, @{n='ComputerName';e={$_.name}}

The old way uses lowercase l (L) and/or Label for name which was confused with 1 (one).

So, to hook up two pipes that don't ordinarily have common paramerters:

get-adcomputer -fileter * | select -property @{n='ComputerName';e={$_.name}} | get-service -name bits

Wmi example. Get-WmiObject does not take pipeline input:

get-wmiobject -class win32_bios
get-wmiobject -class win32_bios -ComputerName dc,s3
get-adcomputer -filter * | get-wmiobject -class win32_bios 
get-adcomputer -fileter * | gm
get-help get-wmiobject -full #has no pipeline input
get-adcomputer -filter * | select -ExpandProperty name #give just the names
get-wmiobject -class win32_bios -ComputerName (get-adcomputer -filter * | select -ExpandProperty name).name
get-wmiobject -class win32_bios -ComputerName (get-adcomputer -filter * ).name

Updated method that uses pipeline input

get-help get-CimInstance

Script parameters

get-adcomputer -filter * | get-wmiobject -class win32_bios -ComputerName {$_.name}

output

Send data to the terminal, but not the pipeline

write-host

Send data to the terminal and the pipeline

write-output

Yellow text by default

write-warning "Please don't do that"

Red text

write-error "Stop touching me!"
1..5
1..5 > $test.txt
${z:\sandbox\test.txt}
${z:\sandbox\test.txt} = "New file data overwites old file data!"
${z:\sandbox\test.txt} = ${z:\sandbox\test.txt} + "New file data appended."

Network Adapter

Using WMI

Get-NetworkAdapterStatus.ps1

<#
   .Synopsis
    Produces a listing of network adapters and status on a local or remote machine.
   .Description
    This script produces a listing of network adapters and status on a local or remote machine.
   .Example
    Get-NetworkAdapterStatus.ps1 -computer MunichServer
    Lists all the network adapters and status on a computer named MunichServer
   .Example
    Get-NetworkAdapterStatus.ps1
    Lists all the network adapters and status on local computer
   .Inputs
    [string]
   .OutPuts
    [string]
   .Notes
    NAME:  Get-NetworkAdapterStatus.ps1
    AUTHOR: Ed Wilson
    LASTEDIT: 1/10/2014
    KEYWORDS: Hardware, Network Adapter
   .Link
     Http://www.ScriptingGuys.com
#Requires -Version 2.0
#>

Param(
  [string]$computer= $env:COMPUTERNAME
) #end param

function Get-StatusFromValue
{
 Param($SV)

 switch($SV)
  {
   0 { " Disconnected" }
   1 { " Connecting" }
   2 { " Connected" }
   3 { " Disconnecting" }
   4 { " Hardware not present" }
   5 { " Hardware disabled" }
   6 { " Hardware malfunction" }
   7 { " Media disconnected" }
   8 { " Authenticating" }
   9 { " Authentication succeeded" }
   10 { " Authentication failed" }
   11 { " Invalid Address" }
   12 { " Credentials Required" }
   Default { "Not connected" }
  }

} #end Get-StatusFromValue function


# *** Entry point to script ***

# PowerShell 2.0
Get-WmiObject -Class win32_networkadapter -computer $computer |
Select-Object Name, @{LABEL="Status";
 EXPRESSION={Get-StatusFromValue $_.NetConnectionStatus}}

# PowerShell 3.0
Get-CimInstance -ClassName win32_networkadapter |
Select-Object Name, @{LABEL="Status";
 EXPRESSION={Get-StatusFromValue $_.NetConnectionStatus}}

Using Net-Adapter (Windows 8 and 8.1)

Get-NetAdapter

Reduce to Physical

Get-NetAdapter -physical

Now only the “Up” adapter

Get-NetAdapter -physical | where status -eq 'up'

Twitter #powershell @jsnover

MVA - Scripting Toolmaking

Get code from powershell.org: https://powershell.org/2013/07/29/mva-powershell-jumpstart-2-scripts-for-aug-1st/

Invoke-Item to open current location

ii .

Unblock file to unblock files from execution since the example scripts are blocked from execution

unblock-File *\* -Verbose

Variables

Variables with spaces can be wrapped in {}

$MyVar=2
${My Var}="Hello"
${My Var}

User Write-Output in scripts

Write-Output $MyVar

Control variable type to help generate proper help

[string]$MyName="Steve"
[int]$Oops="string" # failed by design
$x = [int]"1" #casts 1 to an integer
$x = "test" #assumes string and changes the type of the var
[int]$x = "1" #types the variable as int

Stores date as a string of characters

$d = “9/19/2017” Intelesense or gm will give string functions

Store date as date/time object

[datetime]$d = "9/19/2017"

Will give different properties, methods and functions

$d.dayofweek
$.AddDays(- (7*6))

Validate variable data to only a, b or c:

[validateset("a","b","c")][string]$x = "a"

Quote strength

Double quotes will resolve variables and single will not. To print a $, escape it with a backtick

"This is the variable $i, and $i Rocks!" #prints the variable contents
'This is the variable $i, and $i Rocks!' #prints the variable name exactly as in the single quootes
"This is the variable `$i, and $i Rocks!" #prints the first variable name and resolves the second one

Variable expansion

$p = get-process lsass
"Process id = $($p.id)"
"Process id = $(read-host "What should I give them?")"

HERE strings

“HERE string” is a multiline string. Snipits use them, which can be user created.

@' #begin string



# end of string
'@

Use a HERE string to create an ISE code snipit by assigning the HERE contents to a variable and running the assignment command in ISE (select code and run selection). Search for snipit in the command window and select New-IseSnipit. Then put the variable name in the Text* file of the snipit and run the snipit command.

Sub expressions

$Msg="Service Name is $($service.name.ToUpper())"

Range Operator

1..5
5..1
1..-1 #Goes to the end of the array

Parenthesis

Do what is inside the parethesis first.

get-service -computername (import-csv c:\computers.csv | select -expandproperty computername)

PS v3:

get-service -computername (import-csv c:\computers.csv).computername

To just the names, use expandproperty

import-csv c:\Computers.csv | select-object -expandproperty computername

Logical Constructs (if, then)

if

If ($this -eq $that) {
  # commands
} elseif ($those -ne $them) {
  # commands
} elseif ($we -gt $they) {
  # commands
} else {
  # commands
}

$y = if ($false) {“1”} else {“2”}

Switch

Switch ($status) {
  0 { $status_text = 'ok' }
  1 { $status_text = 'error' }
  2 { $status_text = 'jammed' }
  3 { $status_text = 'overheated' }
  4 { $status_text = 'empty' }
  default { $status_text = 'unknown' }
}

$status_text = Switch ($status) {
  0 { 'ok' }
  1 { 'error' }
  2 { 'jammed' }
  3 { 'overheated' }
  4 { 'empty' }
  default { 'unknown' }
}

Looping Constructs

Do

# Do loop
$i= 1
Do {
    Write-Output "PowerShell is Great! $i"
    $i=$i+1 # $i++ # i+=2 # $i--
} While ($i -le 5) #Also Do-Until

While

# While Loop
$i=5
While ($i -ge 1) {
    Write-Output "Scripting is great! $i"
    $i--
}

For, For Each, ForEach-Object

$services = Get-Service
ForEach ($service in $services) {
  $service.Displayname #$item would be a good variable or $s is even easier to read.
}

#For loop
For ($i=0;$i –lt 5;$i++) {
 #do something
}

#Another way
1..5 | ForEach-Object -process { # abbreviated with a percent sign %
    Start calc
}

Template

Code blocks can run just at the begining and end, but process blocks on each object passed to the function

<#
 Comment based help
#>
Function Verb-Noun {

    [CmdletBinding()]
    Param(
        [Parameter()][String]$MyString,
        [Parameter()][Int]$MyInt
    )

    Begin{<#Code#>}
    Process{<#Code#>}
    End{<#Code#>}
}

Parameters

switch

Switch parameters allows -switches to be evaluated.

Powershell generally uses only singular variable names because English plurality rules are irregular.

write-verbose requires the -verbose switch to be added to get any output

The @{ } is a hash table which that allows custom field names to be applied, but the sort order will be random unless [ordered] is used.

Function Get-CompInfo{
    [CmdletBinding()]
    Param(
        #Want to support multiple computers
        [String[]]$ComputerName,
        #Switch to turn on Error logging
        [Switch]$ErrorLog,
        [String]$LogFile = 'c:\errorlog.txt'
    )
    Begin{
        If($errorLog){
                Write-Verbose 'Error logging turned on'
            } Else {
                Write-Verbose 'Error logging turned off'
            }
            Foreach($Computer in $ComputerName){
                Write-Verbose "Computer: $Computer"
            }    
    }
    Process{
        foreach($Computer in $ComputerName){
            $os=Get-Wmiobject -ComputerName $Computer -Class Win32_OperatingSystem
            $Disk=Get-WmiObject -ComputerName $Computer -class Win32_LogicalDisk -filter "DeviceID='c:'"
            
            $Prop=@{ #With or without [ordered]
                'ComputerName'=$computer;
                'OS Name'=$os.caption;
                'OS Build'=$os.buildnumber;
                'FreeSpace'=$Disk.freespace / 1gb -as [int]
            }
        $Obj=New-Object -TypeName PSObject -Property $Prop 
        Write-Output $Obj

        } 
    }
    End{}

}

Pipe to clip

copy to the clipboard

get-help about_Functions_advanced_parameters | clip

then paste to a document

Error Handling

Error Action Preferences

$errorActionPreference
dir variable:*pref*

switches can be used on commands to temporarily change the error action and error variable

  • -ea
  • -ev e

$e contains the array of error objects

$e[0] | fl * -force

Display errors:

$myError
$e.targetobject
foreach ($t in $e.targetobject) { $t }

Category View

dir variable:*error*
$errorview = "Normalview"

generate some errors

stop-process -id 13
asdfas
$errorview = "CategoryView:

generate some errors

stop-process -id 13
asdfas

The view will be different

Event Log

This also needs to be registered to work

write-EventLog -LogName Application -Source JasonSavesYouMoney -EntryType Information -Message "Sxript foo ran" -EventID 7

Tools that make changes

Add commandlet binding

[cmdletbinding(SupportsShouldProcess=$true,
                ConfirmImpact='Medium")]

Add the switch -whatif or -confirm and -verbose

  • whatif will not run the code
  • confirm will ask
  • verbose will run the code, but give more information

Default views

\Windows\system32\WindowsPowerShell\v1.0\DotNetTypes.format.ps1xml

built in views

Give garbage view name to get error message the tells the view names

gps * | format-table -view blahblah

process, priority, selection

gps * | format-table -view priority
gps * | sort priority | format-table -view 
gps * | sort starttime | format-table -view 

pstypenames

$x = gps lsass
$x.GetType()
$x.pstypenames
$x.pstypenames.Insert(0, "anything you want")
$x.pstypenames

Examine the type name of the results from the following command

Get-EventLog -LogName Application -Newest 3 | gm
$x = Get-EventLog -LogName Application -Newest 3 | gm
$x.pstypenames

The previous will show synthesized names that simplify or parse the results

From the examples

$obj=New-Object -TypeName PSObject -Property $Prop
$obj.PSObject.TypeNames.Insert(0,'Jason.InventoryObject')
$obj.PSTypeNames.Insert(0,'Jason.InventoryObject')

Other Randomness

Network exploration

Get-WmiObject -Class Win32_NetworkAdapterConfiguration -Filter IPEnabled=false | Select-Object description | %{ $_.description } | measure | %{ $_.count }
Get-WmiObject -Class Win32_NetworkAdapterConfiguration -Filter IPEnabled=true| Where-Object {$_.IPAddress -like "128.173.*" -or $_.IPAddress -like "198.82.*" } | Select-Object description, | %{ $_.description }
$nic = Get-WmiObject -Class Win32_NetworkAdapterConfiguration -Filter IPEnabled=true| Where-Object {$_.IPAddress -like "128.173*" } | Select-Object description
Get-WmiObject -Class Win32_NetworkAdapterConfiguration -Filter IPEnabled=true| format-list description, IPAddress, DNSServerSearchOrder
Get-WmiObject -Class Win32_NetworkAdapterConfiguration -Filter IPEnabled=true| Select-Object * | Out-GridView

$NA = Get-WmiObject -Class CIM_NetworkAdapter -filter DeviceID=7
$NA.Properties | Select-Object name,value
$NA.Properties.Item("Netconnectionid").value
$NA.Properties.Item("Name").value

#Get-WmiObject -Class Win32_NetworkAdapterConfiguration -Filter IPEnabled=TRUE -ComputerName . |
# something

#Get-WmiObject -Class Win32_NetworkAdapterConfiguration -Filter IPEnabled=TRUE | Format-List *

#netsh interface ipv6 6to4 set state disabled
#netsh interface teredo set state disabled
#netsh interface ipv6 isatap set state disabled

( nslookup orion.aoe.vt.edu 128.173.188.26 | select-string "128" ).count

#netsh interface ip set dns "Local Area Connection" static 128.173.188.25
#netsh interface ip set dns "Local Area Connection" static 128.173.188.26
#netsh interface ipv6 add dnsserver "Local Area Connection" static 2001:468:c80:610c:ccfb:66e9:490f:d18
#netsh interface ipv6 add dnsserver "Local Area Connection" static 2001:468:c80:610c:d1cd:8142:30a:3a7a
#netsh interface ipv6 add dnsserver "Local Area Connection" static 2001:468:c80:610c:d1cd:8142:30a:3a7a

$DC = "128.173.188.25,128.173.188.26"
$Internet = "8.8.8.8"
$dns = "$DC", "$Internet"
$Interface = Get-WmiObject Win32_NetworkAdapterConfiguration 
Write-Host "$(Get-Date -format T):Registering DNS $dns for $server" -ForegroundColor Green
Write-Host $Interface.Name

Computer System information

get-wmiobject -Class win32_computersystem

Adtive Directory queries

Get-ADComputer -SearchBase "OU=vpfin,OU=central,DC=cntrlsrvs,DC=w2k,DC=vt,DC=edu" -Filter *

Get-ADUser -server sawbones -SearchBase "OU=aoe,OU=vt,DC=w2k,DC=vt,DC=edu" -SearchScope 2 -Filter *

( Get-ADUser nomitav -properties * ) | Select-Object displayname, description, unixhomedirectory, whencreated, whenchanged, userpricipalname, passwordlastset | format-list

cntrlsrvs.w2k.vt.edu

University Active Directory

Two domains relevant to AOE. the first one seems to be the parent domain

  • w2k.vt.edu
    • HOKIES users (and computers?)
    • sawbones.cc.vt.edu
    • gordon.cc.vt.edu
  • cntrlsrvs.w2k.vt.edu
    • cntrlsrvs(?) users and computers
    • aoe has an OU in this domain
    • cntrlsrvsdc1.cntrlsrvs.w2k.vt.edu
    • cntrlsrvsdc2.cntrlsrvs.w2k.vt.edu
    • aoe-hokies-users group is added in this domain with the members of the AOE users in w2k.vt.edu/vt/aoe

Querering w2k.vt.edu works:

Get-ADUser -server sawbones -SearchBase "OU=aoe,OU=vt,DC=w2k,DC=vt,DC=edu" -SearchScope 2 -Filter *

But cntrlsrvs.w2k.vt.edu not work as of recently (works now):

get-adcomputer -SearchBase "OU=aoe,OU=central,DC=cntrlsrvs,DC=w2k,DC=vt,DC=edu" -Filter *
  get-adcomputer : Unable to find a default server with Active Directory Web Services running.

Work-around as posted by techsupport user:

new-psdrive -PSProvider ActiveDirectory -Name "AD" -Root "" -Server "w2k.vt.edu" -GlobalCatalog -Credential (get-credential)
cd AD:\
get-adcomputer -SearchBase "OU=aoe,OU=central,DC=cntrlsrvs,DC=w2k,DC=vt,DC=edu" -Filter *

Bigfix integration

ipv6 dns servers

https://developer.bigfix.com/relevance/reference/ipv6-address.html

ipv6 dns server of <network adapter> : ipv6 address 
dns server of <network adapter> : network address list
ipv4or6 dns server of <network adapter> : ipv4or6 address
aoe/powershell.txt · Last modified: 2019/01/23 19:20 by 127.0.0.1