Actions

PowerShell/Core7

From Ever changing code

< PowerShell

Installing PowerShell on Linux

Note: Ubuntu 20.04 is an LTS release. PowerShell does not currently support this version. Support for this version is being considered for the PowerShell 7.1 release. PowerShell can only support the distributions that are supported by .NET. See the Core release notes for a list of supported distributions.

# Centos
curl https://packages.microsoft.com/config/rhel/7/prod.repo | sudo tee /etc/yum.repos.d/microsoft.repo
sudo yum install -y powershell

# Ubuntu
snap install powershell --classic
powershell 7.0.2 from Microsoft PowerShell✓ installed

$ powershell # run or use 'pwsh' to start it up
PowerShell 7.0.2
Copyright (c) Microsoft Corporation. All rights reserved.

https://aka.ms/powershell
Type 'help' to get help.

PS /home/piotr> $PSVersionTable

Name                           Value
----                           -----
PSVersion                      7.0.2
PSEdition                      Core
GitCommitId                    7.0.2
OS                             Linux 5.4.0-1015-aws #15-Ubuntu SMP Thu Jun 4 22:47:00 UTC 2020
Platform                       Unix
PSCompatibleVersions           {1.0, 2.0, 3.0, 4.0…}
PSRemotingProtocolVersion      2.3
SerializationVersion           1.1.0.1
WSManStackVersion              3.0

Concepts

  • $_ - current object
Get-ChildItem /var | ForEach-Object -Process {$_.FullName}
/var/backups
/var/cache
...
  • source a script into the current session . ./functions.ps1. Use get-command functionName to verify loaded functions into the session context. This works similar to Linux shell sourcing.
  • module - set of related Windows PowerShell functionalities grouped together as convenient units
  • Scripts should end with .PS1 so they are loaded and run in the current process and it's expected behaviour of PowerShell. The magic number #! can be used, but script will be run in a new PowerShell instance preventing accessing to current process objects. This might be desirable when executing PowerShell from bash or another shell.
  • help
    • use Get-Member to get a list of available properties of an object
    • search a commands with Get-Command *user*, see filtered example below:
CommandType     Name                                               Version    Source
-----------     ----                                               -------    ------
Alias           Set-AzADUser                                       2.2.0      Az.Resources
Function        Disconnect-AzWvdUserSession                        1.0.0      Az.DesktopVirtualization
Cmdlet          Add-AzApiManagementUserToGroup                     2.0.1      Az.ApiManagement
Cmdlet          Get-AzADUser                                       2.2.0      Az.Resources
Cmdlet          Update-AzADUser                                    2.2.0      Az.Resources
Application     adduser                                            0.0.0.0    /usr/sbin/adduser
Application     adduser                                            0.0.0.0    /sbin/adduser

Environment profiles

Any commands included in the profile file will be executed during terminal/shell initialization. Note: This is not working while switching the shell and is executed on the new terminal initiation

> $profile
/home/piotr/.config/powershell/Microsoft.VSCode_profile.ps1

Pipeline

Everything in PS is an object, although we use '|' piping this is not the same concept as STDIN and STDOUT in Linux.

PS> Get-Process -Name whoopsie | Get-Member -Name CPU,Company
PS> Get-Process -Name whoopsie | Select-Object -Property name,CPU 

Name      CPU
----      ---
whoopsie 0.24

# When assigning to a variable we assign an object not just a string
$variable = Get-Process
S> $variable | Select-Object -Property name,CPU | Sort-Object -Descending CPU | Select-Object -First 5

Name                  CPU
----                  ---
gnome-shell      11796.69
firefox     11012.4599999
Web Content       7573.22
Web Content       5085.47
Xorg              3593.26

Variables

These are objects.

S /home/piotr> Get-Help *variable*
Name                              Category  Module                    Synopsis                                                                                                                                                                                                                                       
----                              --------  ------                    --------
Clear-Variable                    Cmdlet    Microsoft.PowerShell.Uti… …
Get-Variable                      Cmdlet    Microsoft.PowerShell.Uti… …
New-Variable                      Cmdlet    Microsoft.PowerShell.Uti… …
Remove-Variable                   Cmdlet    Microsoft.PowerShell.Uti… …
Set-Variable                      Cmdlet    Microsoft.PowerShell.Uti… …

if

if ($var -gt 5) {
  write-host "true"
} elseif {
  write host "false"
}

do/while

Do {
    $number = $number + 1 
    write-host "current nuber is: $number"
} while ($number -lt 10)

for each

$names = "Bob","Jamse","Tom"
$collection = $names
$count = 0
foreach ($item in $collection) {
    $count += 1
    Write-Host "$item"
}
Write-Host "$count"

Convert

Working with Powershell pipelines it means workign with objects, so we format output but not modifying it. This is power full combination allowing for object/output convertn at any time.

Get-Process | Sort-Object -Descending CPU | Select-Object -First 5 | ConvertTo-Json
# more convert formats
Convert-AzSqlDatabase... ConvertFrom-Json         ConvertFrom-StringData    ConvertTo-Json
Convert-AzSqlInstance... ConvertFrom-Markdown     ConvertTo-AzVMManagedDisk ConvertTo-ScriptExtent
Convert-Path             ConvertFrom-ScriptExtent ConvertTo-Csv             ConvertTo-SecureString
ConvertFrom-Csv          ConvertFrom-SecureString ConvertTo-Html            ConvertTo-Xml

Add calculated property field

# Syntax: @{ Name = '';  Expression = {}}
Get-Process | Select-Object -Property Name, @{ Name = 'MGB'; Expression = {$_.VM / 1gb -as [int]}} | Sort-Object -Property MGB -Descending | Select-Object -First 3
  # MGB - property name; $_  - current object
Name        MGB
----        ---
code         12
gnome-shell   4
pwsh          3


Add a new property to an object by utilising 'ScriptProperty' to enrich an object with extra TypeSet (aka data, column etc.).

Update-TypeData -TypeName System.Diagnostics.process -MemberType ScriptProperty -MemberName MGB -Value {$this.VM/1gb -as [int]}
Get-Process | Get-Member M*
PS /home/piotr> Get-Process | Get-Member M*

   TypeName: System.Diagnostics.Process

Name             MemberType     Definition
----             ----------     ----------
MachineName      Property       string MachineName {get;}
MainModule       Property       System.Diagnostics.ProcessModule MainModule {get;}
(...)
Modules          Property       System.Diagnostics.ProcessModuleCollection Modules {get;}
MGB              ScriptProperty System.Object MGB {get=$this.VM/1gb -as [int];}

Function

function func-name {
  set-location /opt/
}

Multiple scripting languages within Powershell

Using hash doc(aka hash string, hash notastion) we can execute multiple scripting languages within Powershell to bounce between multiple languages. Each output is an object with all PowerShell properties.

@'script.py'@

$index = @"
<html>
<body><p>Hello!</p></body>
</html>
"@

$index | Set-Content index.html # write variable content into the file

PowerShell7 remoting over SSH

# Help on syntax
Get-Command New-PSSession -Syntax

New-PSSession [[-ComputerName] <string[]>] [-Credential <pscredential>] [-Name <string[]>] [-EnableNetworkAccess] [-ConfigurationName <string>] [-Port <int>] [-UseSSL] [-ApplicationName <string>] [-ThrottleLimit <int>] [-SessionOption <PSSessionOption>] [-Authentication <AuthenticationMechanism>] [-CertificateThumbprint <string>] [<CommonParameters>]
New-PSSession [-ConnectionUri] <uri[]> [-Credential <pscredential>] [-Name <string[]>] [-EnableNetworkAccess] [-ConfigurationName <string>] [-ThrottleLimit <int>] [-AllowRedirection] [-SessionOption <PSSessionOption>] [-Authentication <AuthenticationMechanism>] [-CertificateThumbprint <string>] [<CommonParameters>]
New-PSSession [-VMId] <guid[]> -Credential <pscredential> [-Name <string[]>] [-ConfigurationName <string>] [-ThrottleLimit <int>] [<CommonParameters>]
New-PSSession -Credential <pscredential> -VMName <string[]> [-Name <string[]>] [-ConfigurationName <string>] [-ThrottleLimit <int>] [<CommonParameters>]
New-PSSession [[-Session] <PSSession[]>] [-Name <string[]>] [-EnableNetworkAccess] [-ThrottleLimit <int>] [<CommonParameters>]
New-PSSession -ContainerId <string[]> [-Name <string[]>] [-ConfigurationName <string>] [-RunAsAdministrator] [-ThrottleLimit <int>] [<CommonParameters>]
New-PSSession -UseWindowsPowerShell [-Name <string[]>] [<CommonParameters>]
New-PSSession [-HostName] <string[]> [-Name <string[]>] [-Port <int>] [-UserName <string>] [-KeyFilePath <string>] [-SSHTransport] [-Subsystem <string>] [<CommonParameters>]
New-PSSession -SSHConnection <hashtable[]> [-Name <string[]>] [<CommonParameters>]


Ssh session

# Install packages
sudo apt install openssh-server openssh-client

# Ssh-server 'sshd_config' adjustments for 'pssession' to make it work
sudo vi /etc/ssh/sshd_config
PasswordAuthentication yes
PubkeyAuthentication yes
Subsystem powershell /usr/bin/pwsh -sshs -NoLogo -NoProfile                   # depends on your OS
# Subsystem powershell /snap/powershell/132/opt/powershell/pwsh -sshs -NoLogo # <- Ubuntu 20.04 uses snap package

# PSSession
Entry-PSSession -HostName 127.0.0.1 -UserName piotr # get into ssh session
[localhost]: PS /home/piotr> 

New-PSSession -HostName 127.0.0.1 -UserName piotr   # create an object
piotr@localhost's password: 
 Id Name            Transport ComputerName    ComputerType    State         ConfigurationName     Availability
 -- ----            --------- ------------    ------------    -----         -----------------     ------------
 12 Runspace11      SSH       localhost       RemoteMachine   Opened        DefaultShell             Available

File manipulation

# Output to a file
Get-Process | head | ConvertTo-Json | Out-File output.json # saves 10 top lines using Linux command

# Read a file content
$data = Get-Content ./output.json | ConvertFrom-Json

# This is still an object, check 'get-member' or using 'measure' you can see that only 10 lines have been selected
$data | Sort-Object -Descending CPU | measure

Cloud provider tools

AWS

AWS Tools

Get-Module # get currently installed modules
Get-Module -ListAvailable -Refresh

# Aws Tools
Install-Module -Name AWS.Tools.Installer -Force
Install-AWSToolsModule AWS.Tools.EC2,AWS.Tools.S3 -CleanUp
Get-AWSPowerShellVersion -ListServiceVersionInfo

Install-Package -Name AWSPowerShell.NetCore # install a software from PSGallery
Install-Module -Scope CurrentUser -Name AWSPowerShell.NetCore -Force
Install-Module -name AWSPowerShell.NetCore
Install-Module -name AWSPowerShell.NetCore -Force # force untrusted repository
Import-Module AWSPowerShell.NetCore # import the module and bring into our profile

Get-Command -Module AWSPowerShell.NetCore | Out-Null # piped to null-out as there is over 4k commands
Get-Command *aws* # display avaialble AWS cmdlets

# Set credentials
Set-AWSCredentials -AccessKey AKI... -secretKey Zo... -StoreAs aws-profile-1
Get-AWSCredential -ListProfileDetail
ProfileName   StoreTypeName         ProfileLocation
-----------   -------------         ---------------
aws-profile-1 SharedCredentialsFile /home/piotr/.aws/credentials

# Preview credentials file
Get-Content /home/piotr/.aws/credentials
[aws-profile-1]
aws_access_key_id=AKI...
aws_secret_access_key=Zo...

# Set default AWS profile
Set-AWSCredentials -ProfileName aws-profile-1


Manage a resource

PS> New-S3Bucket -BucketName foo123example-powershel7
PS> Get-S3Bucket
CreationDate        BucketName
------------        ----------
17/07/2020 13:10:39 foo123example-powershel7

# Upload a file
PS> Write-S3Object -File ./.bashrc -BucketName foo123example-powershel7

# List files
PS1> Get-S3Object -BucketName foo123example-powershel7                  
ETag         : "fe225aefed67a397fd160d5a0b4e7e35"
BucketName   : foo123fffowjkgpowj
Key          : .bashrc
LastModified : 17/07/2020 13:41:50
Owner        : Amazon.S3.Model.Owner
Size         : 5655
StorageClass : STANDARD

GCP Google Cloud Platform

Note: Please be aware that GoogleCloud module may not support all security services or operations, but with each release more covarage is being added on

Install gcloud cli

Install Powershell GoogleCloud

PS> Install-Package GoogleCloud
Name                           Version          Source           Summary                                                                                                              ----                           -------          ------           -------                                                                                                              GoogleCloud                    1.0.1.10         PSGallery        PowerShell cmdlets for the Google Cloud Platform. 

# As part of the import you will be prompted to install 'gcloud' utility and Google Cloud SDK
PS> Import-Module GoogleCloud
PS> Get-Module

ModuleType Version    PreRelease Name                                ExportedCommands
---------- -------    ---------- ----                                ----------------
Script     1.0.1.10              GoogleCloud                         {Add-GcdChange, Add-GcdManagedZone, Add-GceAddress, Add-GceFirewall…}
(...clipped)

Get-Command -Module GoogleCloud # get all Cmdlets added


Create and delete a resource

New-GcsBucket -Name bucket-1-fkwejafp  # bucket name need to be globally unique DNS compliant formatted name
Name              TimeCreated         Updated
----              -----------         -------
bucket-1-fkwejafp 07/06/2020 08:07:07 07/06/2020 08:07:07

PS> Get-GcsBucket -Name bucket-1-fkwejafp | measure # Note there is just one object

Count             : 1
Average           : 
Sum               : 
Maximum           : 
Minimum           : 
StandardDeviation : 
Property          :

PS> Get-GcsBucket -Name bucket-1-fkwejafp | Remove-GcsBucket # pipe that object to 'remove-' cmdlet
PS> Get-GcsBucket -Name bucket-1-fkwejafp
Get-GcsBucket: Storage bucket 'bucket-1-fkwejafp' does not exist.

# Create VM
$disk = Get-GceImage "windows-cloud" -Family "windows-2012-r2"
$config = New-GceInstanceConfig "my-vm-1"   -MachineType "n1-standard-4"  -DiskImage $disk
$config | Add-GceInstance -Project $project -Zone us-central1-b

Get-GceInstance -Name my-vm-1 -Zone us-central1-b

Name    CpuPlatform   MachineType   Zone          TimeCreated
----    -----------   -----------   ----          -----------
my-vm-1 Intel Haswell n1-standard-4 us-central1-b 2020-07-17T06:36:37.018-07:00

$instance = Get-GceInstance "my-vm-1"
Stop-GceInstance $instance
Set-GceInstance $instance -AddMetadata @{"newKey" = "newValue"} # in UI it's called 'Custom metadata'

Azure

Install Az Microsoft Azure PowerShell from PowerShell Gallery or as alternative use PowerShellGet.

Install-Module -Name Az
Import-Module Az
Get-Module # lists all new available commands
Get-Module -name Az -ListAvailable # include modules source directory



References