====== 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 >>> { >>> $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 ==== Microsoft scriptcenter https://gallery.technet.microsoft.com/scriptcenter/ ==== 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 "

Generated by IT

" -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 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 -InputObject 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 ====== https://blogs.technet.microsoft.com/heyscriptingguy/2014/01/15/using-powershell-to-find-connected-network-adapters/ ===== 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 : ipv6 address dns server of : network address list ipv4or6 dns server of : ipv4or6 address