Power Shell: Difference between revisions

From vwiki
Jump to navigation Jump to search
m (→‎Get-Credential: Fix typo)
m (Typo fix)
 
(93 intermediate revisions by the same user not shown)
Line 1: Line 1:
== Getting Started ==
#REDIRECT [[:Category:PowerShell]]
=== Useful Sites ===
Subject specific useful links are listed in the sections below, the following provide links to installers and general documentation
* [http://www.microsoft.com/windowsserver2003/technologies/management/powershell/download.mspx Windows PowerShell V1]
* [http://support.microsoft.com/kb/968929 Windows PowerShell V2]
* http://powershell.com/cs/ - Good all-round help
* http://technet.microsoft.com/en-us/library/bb978526.aspx - TechNet!
 
=== Installed Version ===
To check the main installed version use the following command...
<source lang="powershell"> get-host | select version </source>.
However, if you might have installed something other than the normal RTM or GA release version you'll need to the registry key <code>HKLM\Software\Microsoft\PowerShell\1</code>, which will have the following values of interest...
{|cellpadding="1" cellspacing="0" border="1"
|- style="background-color:#bbddff;"
! Value                !! Data                                !! Meaning
|-
|<code> Install </code> || <code>1</code>                      || Installed (not version number)
|-
|<code> PID </code>    || <code>89383-100-0001260-04309</code> || RTM (Release to Manufacturing)
|-
|<code> PID </code>    || <code>89393-100-0001260-00301</code> || RC2 (Release Candidate 2)
|}
For more info on release version acronyms, see [http://en.wikipedia.org/wiki/Software_release_life_cycle Software Release Life Cycle]
 
=== Help Commands ===
<source lang="powershell">Get-Help <cmd>              # Provides help for CmdLets, use wildcards to broaden results.
<object> | Get-Member      # Provides information about an object</source>
 
== Variables ==
All variable names are prefixed with a $, and are case '''insensitive''' (though there's no reason to not use CamelBack notation if that floats your boat).
 
Apart from a few reserved words and characters there's little restriction on what can be used, though note that this flexibility can cause the occasional issue, whereby PowerShell gets confused as to where a variable name finishes. Variable names can be enclosed in <code> { } </code> in order to delimit them, eg <code>${varname}</scode>.
 
Powershell is all about manipulating objects, and its variables are all essentially the same, not being specifically defined as an object, string, integer, etc. Which is normally useful, however sometimes you need to force a variable to contain a data type. Using a prefix of [type] achieves this...
<source lang="powershell"> [string]$result = $PingResult.Status </source>
 
{|cellpadding="1" cellspacing="0" border="1"
|- style="background-color:#bbddff;"
! Notation                      !! Data Type
|-
|<code> [bool] </code>  || True / false
|-
|<code> [single] </code> || Single-precision 32-bit floating point number
|-
|<code> [double] </code> || Double-precision 64-bit floating point number
|-
|<code> [byte] </code> || 8-bit unsigned character
|-
|<code> [int] </code> || 32-bit integer
|-
|<code> [long] </code> || 64-bit integer
|-
|<code> [decimal] </code> || 128-bit decimal
|-
|<code> [char]  </code> || Single character
|-
|<code> [string] </code> || String of characters
|-
|<code> [datetime] </code>      || Date or time
|-
|<code> [xml] </code> || XML object
|-
|<code> [array] </code> || Array
|-
|<code> [wmi] </code> || Windows Management Instrumentation (WMI) instance or collection
|-
|<code> [wmiclass] </code> || WMI class
|-
|<code> [adsi] </code> || Active Directory Services object
|-
|<code> [Boolean] </code> || True or False value
|}
 
=== Variable Information ===
As variables tend to be black boxes that can contain anything or nothing, its often necessary to understand more about one...
 
'''Variable Type'''
<source lang="powershell">
$var.GetType()
IsPublic IsSerial Name                                    BaseType
-------- -------- ----                                    --------
True    True    Object[]                                System.Array
</source>
 
'''Variable Properties and Methods'''
<source lang="powershell">
Get-Member -InputObject $var
</source>
 
=== Strings ===
'''Concatenation +'''
<source lang="powershell">
$strAB = $strA + $strB
</source>
 
<br>'''Interpolation''' <br>
Interpolation allows variables to be embedded into a string and to be resolved into their actual values.  This works between double quotes, but not between single quotes...
<source lang="powershell">
PS E:\> $sub = "replaced"
PS E:\> Write-Output "Variable has been $sub"
Variable has been replaced
PS E:\> Write-Output 'Variable has been $sub'
Variable has been $sub
</source>
 
<br>'''Replace''' <br>
Basic find and replace can be done with the Replace CmdLet, eg to replace "\" with "\\" in the $query variable...
<source lang="powershell"> $query = $query.Replace("\", "\\") </source>
For proper regular expressions support, use the following syntax
<source lang="powershell"> $query = [regex]::Replace($query, "search", "replace") </source>
 
== Credentials ==
=== Get-Credential ===
When running commands that require a connection to a remote machine its useful to be able to store a user/pass combination so that you aren't repeatedly prompted every time you run a command.  Create a credential object, then supply that in place of a username in a command
 
<source lang="powershell">
PS H:\> $cred = Get-Credential
 
cmdlet Get-Credential at command pipeline position 1
Supply values for the following parameters:
Credential
PS H:\> Get-WMIObject -query "SELECT * FROM Win32_OperatingSystem" -credential $cred -computer 159.104.224.167
 
SystemDirectory : C:\WINDOWS\system32
Organization    : TF
BuildNumber    : 3790
RegisteredUser  : TF
SerialNumber    : 69712-640-3560061-45009
Version        : 5.2.3790
</source>
 
However, this doesn't really help much in a fully scripted situation where you need to supply user and pass in an unattended fashion, for that you also need the help of <code> ConvertTo-SecureString </code>
 
=== ConvertTo-SecureString ===
* http://technet.microsoft.com/en-us/library/dd819512.aspx
* Converts encrypted standard strings to secure strings
 
== WMI ==
 
Cmdlet for using WMI via PowerShell is '''Get-WMIObject''', which has an alias of '''gwmi''', for example...
 
<source lang="powershell">
PS H:\> Get-WMIObject -query "Select * from Win32_OperatingSystem"
 
SystemDirectory : C:\WINDOWS\system32
Organization    :
BuildNumber    : 2600
RegisteredUser  : TF
SerialNumber    : 76487-OEM-0011903-00102
Version        : 5.1.2600
 
PS H:\> Get-WMIObject -query "SELECT * FROM Win32_UTCTime"
 
__GENUS          : 2
__CLASS          : Win32_UTCTime
__SUPERCLASS    : Win32_CurrentTime
__DYNASTY        : Win32_CurrentTime
__RELPATH        : Win32_UTCTime=@
__PROPERTY_COUNT : 10
__DERIVATION    : {Win32_CurrentTime}
__SERVER        : L-0STRUTTS1
__NAMESPACE      : root\cimv2
__PATH          : \\L-0STRUTTS1\root\cimv2:Win32_UTCTime=@
Day              : 27
DayOfWeek        : 4
Hour            : 10
Milliseconds    :
Minute          : 0
Month            : 8
Quarter          : 3
Second          : 1
WeekInMonth      : 5
Year            : 2009
 
PS H:\> Get-WMIObject -query "Select * from Win32_OperatingSystem" -credential sysmgr -computer ukpgemon2
 
SystemDirectory : C:\WINDOWS\system32
Organization    : Thomson Financial
BuildNumber    : 3790
RegisteredUser  : Dell Image Rev 1
SerialNumber    : 69712-640-3560061-45321
Version        : 5.2.3790
 
PS H:\> Get-WMIObject -query "Select * from Win32_userAccount WHERE Domain = 'OCM-WCS1' AND Name = 'pptp_ypos'" -credential administrator -computer 159.104.224.167
AccountType : 512
Caption    : OCM-WCS1\pptp_ypos
Domain      : OCM-WCS1
SID        : S-1-5-21-2453442427-2400495818-1845097998-1073
FullName    : Ypos-Consulting GmbH
Name        : pptp_ypos
</source>
 
 
=== Find Classes and Properties ===
 
In order to find the correct class use...
<source lang="powershell">
Get-WMIObject -list -credential $cred -computer 159.104.224.167 | Select-String -InputObject {$_.Name} Win32*
</source>
 
To then see all the properties of a class use (doesn't work on remote machines (access denied) - this is a known bug in Power Shell v1)...
<source lang="powershell">
Get-WMIObject Win32_BIOS | Format-List *
</source>
 
[http://technet.microsoft.com/en-gb/magazine/2009.02.windowspowershell.aspx TechNet article: Windows PowerShell Best Inventory Tool Ever!]
 
== Network ==
=== Ping ===
<pre>
PS H:\> $objPing = New-Object system.Net.NetworkInformation.Ping
PS H:\> $objPing.Send('127.0.0.1')
 
Status        : Success
Address      : 127.0.0.1
RoundtripTime : 0
Options      : System.Net.NetworkInformation.PingOptions
Buffer        : {97, 98, 99, 100...}
</pre>
 
=== Name/Address Resolution ===
'''IP to Name'''
* Be aware, where no name can be found, the call throws an exception.  If assigning result to a variable, then it seems to return the local hostname, which is odd.
<pre>
PS H:\> [System.Net.Dns]::GetHostbyAddress("159.104.31.83")
 
HostName                                Aliases                                AddressList
--------                                -------                                -----------
L-STRUTTS1                              {}                                      {159.104.31.83}
</pre>
 
'''Name to IP'''
<pre>
PS H:\> [System.Net.Dns]::GetHostAddresses("l-strutts1")
 
Address          : 1394567327
AddressFamily    : InterNetwork
ScopeId          :
IsIPv6Multicast  : False
IsIPv6LinkLocal  : False
IsIPv6SiteLocal  : False
IPAddressToString : 159.104.31.83
</pre>
 
== MySQL ==
=== Connect ===
<source lang="powershell">
function ConnectMySQL([string]$user,[string]$pass,[string]$MySQLHost,[string]$database) {
  # Load MySQL .NET Connector Objects
  [void][system.reflection.Assembly]::LoadWithPartialName("MySql.Data")
 
  # Open Connection
  $connStr = "server=" + $MySQLHost + ";port=3306;uid=" + $user + ";pwd=" + $pass + ";database="+$database+";Pooling=FALSE"
  $conn = New-Object MySql.Data.MySqlClient.MySqlConnection($connStr)
  $conn.Open()
  return $conn
}
 
function DisconnectMySQL($conn) {
  $conn.Close()
}
 
# So, for example...
 
# Connection Variables
$user = 'myuser'
$pass = 'mypass'
$database = 'mydatabase'
$MySQLHost = 'database.server.com'
 
# Connect to MySQL Database
$conn = ConnectMySQL $user $pass $MySQLHost $database
</source>
 
=== Commands ===
All database operations are done through methods of the <code> MySqlCommand </code> object, the two methods of main interest are...
* '''ExecuteNonQuery''' - Used for queries that don't return any real information, such as an INSERT, UPDATE, or DELETE.
* '''ExecuteReader''' - Used for normal queries that return multiple values.  Results need to be received into <code> MySqlDataReader </code> object.
* '''ExecuteScalar''' - Used for normal queries that return a single.  The result needs to be received into a variable.
 
'''Non-Query'''
<source lang="powershell">
function ExecuteMySQLNonQuery($conn, [string]$query) {
  $command = $conn.CreateCommand()                  # Create command object
  $command.CommandText = $query                    # Load query into object
  $RowsInserted = $command.ExecuteNonQuery()        # Execute command
  $command.Dispose()                                # Dispose of command object
  if ($RowsInserted) {
    return $RowInserted
  } else {
    return $false
  }
}
 
# So, to insert records into a table
$query = "INSERT INTO test (id, name, age) VALUES (1, 'Joe', 33)"
$Rows = ExecuteMySQLNonQuery $conn $query
Write-Host $Rows " inserted into database"
</source>
 
'''Reader Query'''
In theory, this should work, but it doesn't seem to for me.  There's something wrong with the <code>while ($results.Read())</code>, in that you end up displaying the last row returned by the SQL query multiple times.  Suspect its due to the way that a Reader object only seems to hold a result temporarily.
<source lang="powershell">
$query = "SELECT * FROM subnets;"
$cmd = $connMySQL.CreateCommand()
$cmd.CommandText = $query
$results = $cmd.ExecuteReader()
$cmd.Dispose()
while ($results.Read()) {
  for ($i= 0; $i -lt $reader.FieldCount; $i++) {
      write-output $reader.GetValue($i).ToString()
  }
}
</source>
 
Instead, this approach seems to work more reliably.  By loading the data into a dataset, it becomes available for offline manipulation and isn't reliant on the database once the data is loaded in.
<source lang="powershell">
function ExecuteMySQLQuery([string]$query) {
  # NonQuery - Insert/Update/Delete query where no return data is required
  $cmd = New-Object MySql.Data.MySqlClient.MySqlCommand($query, $connMySQL)    # Create SQL command
  $dataAdapter = New-Object MySql.Data.MySqlClient.MySqlDataAdapter($cmd)      # Create data adapter from query command
  $dataSet = New-Object System.Data.DataSet                                    # Create dataset
  $dataAdapter.Fill($dataSet, "data")                                          # Fill dataset from data adapter, with name "data"             
  $cmd.Dispose()
  return $dataSet.Tables["data"]                                              # Returns an array of results
}
 
# So, to produce a table of results from a query...
$query = "SELECT * FROM subnets;"
$result = ExecuteMySQLQuery $query
Write-Host "Found" ($result.Length) "rows..."
$result | Format-Table
</source>
 
'''Scalar Query'''
 
'''Other'''
<source lang="powershell">
$cmd = New-Object MySql.Data.MySqlClient.MySqlCommand("USE $database", $conn)
</source>
 
== Exceptions and Error Handling ==
* http://huddledmasses.org/trap-exception-in-powershell/ - Exception trapping
* http://www.pluralsight.com/community/blogs/keith/archive/2007/01/22/45814.aspx - Error handling
 
To control how a script behaves as a result of an exception, modify the <code> $ErrorActionPreference </code> variable, if required.
 
{|cellpadding="1" cellspacing="0" border="1"
|- style="background-color:#bbddff;"
! Value            !! Effect
|-
| Continue          || [Default] Outputs error, but keeps processing
|-
| SilentlyContinue  || No output and it keeps going
|-
| Inquire          || Prompt user for action
|-
| Stop              || Outputs error and halts processing
|}
 
 
=== Basic Error Catcher ===
 
If you know where the error is likely to occur, then just place an error catcher immediately after it...
<pre>
if (-not $?) {
    # Handle error here
  }
</pre>
 
[[Category:PowerShell]]
[[Category:WMI]]
[[Category:MySQL]]

Latest revision as of 15:37, 4 October 2016