PowerShell -From Noob to Ninja

I have searched and read many articles about Windows PowerShell but did not find any comprehensive article that take you from basic to advance knowledge specifically related to Internet Information Server and PowerShell Remoting. So i tried to make things easy for you, lets get started

This article is about

  • Introduction
  • Extensions
  • Basics
  • Cmdlets
  • Working with IIS
  • Working with Windows Servers/VMs
  • Deep dive into PowerShell Remoting

You can download it from here

Introduction

Advancing command prompt, Microsoft released Windows Powershell in 14th November 2006, designed by Jeffrey Snover, Bruce Payette and James Truher providing more interactive, powerfull, Multi-paradigm that includes Imperative, pipeline, object-oriented, functional, reflective, providing strongly typed and type safe implicit and dynamic environment. The stable version was released on 29th July, 2015.

Extensions

Following are the supported extensions in powershell

  • .ps1 for Script
  • .psc1 for Console file
  • .psd1 for Data file
  • .ps1xml for XML Document
  • .psm1 for Script Module
  • .pssc for Session Configuration File
  • .cdxml for Cmdlet Definition XML Document

Basics

PowerShell introduced over hundreds of new commands to make powershell more powerful. There are many command that are same as MS-DOS commands.

Hello World

The tradition of programming forefathers is “Hello World”. How we can start without it, So to write this on your terminal use

PS C:> Write-Host Hello World

or

PS C:> echo Hello World

You can create variables in powershell by using $ sign for example

PS C:> $message = 'Welcome to PowerShell'

and then print that variable using

PS C:> echo $message

Getting used to with help is most important in be an expert. To get help in powershell use

PS C:> get-help

You can use get-help command by passing arguments too. For example to get help specifically for “dir” (explained below) use can use

PS C:> get-help dir

This will give you detailed description about using dir command, its name, its syntax, aliases and remarks. For the above command it will give you

  • Name: Get-ChildItem
  • SYNTAX: Get-ChildItem [[-Path]…….
  • Aliases: gci, ls, dir
  • Remarks: Get-Help cannot find files……..

To open the Microsoft site that explains the key word you want to get help of in browser use

PS C:> get-help dir -online

Manipulation with Directories

To list all the item that are in the current directory use the same command as in MS-DOS

PS C:> dir

To change the current directory use the same command as in MS-DOS

PS C:> cd d:

CD stands for Change Directory
To go backwards from current directory again use the same command as in MS-DOS command.

PS C:> cd..

To navigate back to the root directory use

PS C:> cd

you can also use alternative to goto specific directory

PS C:> Set-Location D:

or

PS C:> Set-Location 'D:New FolderNew Folder'

To make new directory use

PS C:>md testDirectory

To delete directory use

PS C:> del testDirectory

System Information

You can get the machine name by using

PS C:> [System.environment]::MachineName

Getting the directory of command line (powershell)

PS C:> [System.environment]::CommandLine

To get the information that whether you system is 64-Bit or not use

PS C:> [System.environment]::Is64BitOperatingSystem

Getting Operating system version use

PS C:> [System.environment]::OSVersion

To get current user name use

PS C:> [System.environment]::UserName

Network Information

Same as MS-DOS you can get your network information using

PS C:> ipconfig

For specifically getting IP address and its detailed information you can use

PS C:> Get-NetIPAdress

or

PS C:> Get-NetIPAdress |  Format-Table

or to only get a single property of IP Address use

PS C:> Get-NetIPAddress | Format-Table -Property IpAddress

for getting mac address you can use

PS C:> GetMac

Looping

To execute loops in powershell use

PS C:> 1..2 | % { // Do Stuff here }

For example

PS C:> 1..2 | % { echo 'In-Loop' }

or

PS C:> 1..2 | % { GetMac }

Cmdlets

There are special commands in powershell that are called cmdlets. They are always typed after the prompt and execute on pressing enter. Cmdlets follow the naming convention of “Verb-Noun”. Cmdlets actually return the object but it appears that they are writing in console. The method of passing cmdlets returned object to another cmdlets is called piping
For example
This will give you the operating system version

PS C:> [System.environment]::OSVersion

but you want to pass this to another cmdlet as an input to display a list for you. For this you will be doing

PS C:> [System.environment]::OSVersion | Format-List

In above command the symbol “|” is piping sign. The above command will get the output of first command and pass it as a pipeline to the second command as an input, So result will be displayed by the second command not the first one.
Few other examples are

PS C:>dir | Get-ItemProperty | Format-List

or use can pass the output of second pipeline to the third and write its output in the text file for example

PS C:> Get-NetIPAddress | Format-Table | Out-File 'D:powerShellOutput.txt'

Working with IIS

To start with remoting we need to import a web administration module, to do that use

PSc C:>Import-Module 'WebAdministration'

May be you wont need that if already imported to check that if module already installed or not use

PS C:>Get-Module -ListAvailable

above command will list all the installed modules in it and you need to search for the web administration module. To make it quick command written below, this will only give you the module information of the given name if it exists

PS C:> Get-Module -ListAvailable webadministration

To get Web Administration related cmdlets use

PS C:> Get-Command -Module WebAdministration

or to be specific for website related cmdlets use

PS IIS:> Get-Command -Module WebAdministration -Noun '*website*'

Changing to IIS directory

To change the current directory to IIS use

PS C:> IIS:

This will change you working directory from local drive to IIS and will now looks like

PS IIS:>

If you check all the directories in IIS by using dir/ls/gci you will get Sites, WebApplications ApplicationPools, and other directories.

PS IIS:> ls

Now change you current directory to Site by using

 PS IIS:> cd Sites

Working with Site in IIS

to view all sites try listing all sites in it by using

PS IISSites:>dir

you will get all the list of already created sites whether they are stopped or running. To get details of specific site use the site name as an argument with the below written command

PS IIS:Sites> Get-Item 'TestSite'

or to be very specific use

PS IIS:Sites> Get-Item 'TestSite' | Select-Object *

To Start a site use

PS IIS:Sites> Start-WebSite 'TestSite'

and to stop it use

PS IIS:Sites> Stop-WebSite 'TestSite'

Creating New Site

PS IIS:Sites> New-Item TestSite

The above command will create the new site but there are many other information associated with the site you need to configure that too, So let use the complete command and i will explain it after that

PS IIS:Sites> New-Item IIS:SitesTestSite -Bindings @{protocol="http"; bindingInformation=":80:www.TestSitePowerShell.com"} -physicalPath C:inetpubwwwrootnewFolder

In above site you are specifying Bindings, Protocol and Physical path. Protocol can be ‘ftp’, ‘https’ or what ever your requirements are. Binding Information include the port number and the binding address that you want to give to a site and physical address the the path of the folder where it physically located in the drive.

Updating properties of Site

To update properties of existing site for example to update binding information of a site or a protocol or port number or physical address the command that is used is

PS IIS:Sites> Set-ItemProperty IIS:SitesTestSite -Name bindings -Value @{protocol="http";bindinginformation="*:80:www.abc.com"}

In above command we use Set-Property to Update property of the element and then we will specify the name of the property that we are updating in above case we are updating bindings and then we are providing its new values

Adding new properties

To add new properties to existing site we use the command written below

PS IIS:> New-ItemProperty IIS:SitesTestSite -Name bindings -Value @{protocol="http";bindinginformation="*:8080:www.xyz.com"}

The above is the example in which i assume that the site is already created but its binding properties are not given at the time of creation, so we are adding it now. Its simple, we just need to use New-Property function with Property name and its values as an argument.

Removing properties

To remove/Clear specific property form existing site use

PS IIS:> Clear-ItemProperty IIS:SitesTestSite -Name bindings

Given the Name of the Property it will be removed from the specified object given as a first argument of the Clear-Property function

Renaming the Site

To rename the site use

PS IIS:> Rename-Item IIS:SitesTestSite TestSiteFromPowerShell

Deleting Site

To delete site from IIS use

PS IIS:Sites> Remove-Item 'TestSiteFromPowerShell'

Working with Servers/VMs

Now that seems thrilling but let me surprise you. To work with any Virtual Machine you just need to connect with it and then you are able to do whatever we have already done above. So lets connect to the server

PS C:> Enter-PSSession -ComputerName abc.xyz.net -Credential abc.xyz.netusername -UseSSL

You need to run this and then a password dialog prompt appears, Enter your password and that all you need to do. You are now connected with the server, for example

[abc.xyz.net]: PS C:UsersusernameDocuments>

you can run same command that to get information like

[abc.xyz.net]: PS C:UsersusernameDocuments> dir
[abc.xyz.net]: PS C:UsersusernameDocuments> Get-NetIPAddress
[abc.xyz.net]: PS C:UsersusernameDocuments> cd
[abc.xyz.net]: PS C:> Write-Host 'Welcome to the Virtual Machine'

You can create sites remotely using powerShell on your servers. Now we are done with commands, lets develop some scripts to see the strength of powershell. Below is the example of a powershell script that creates a new ApplicationPool, create new physical directory and then creates a site in it with all the relevant configuration.

Import-Module WebAdministration
$dirName = 'PowerShellMagic'
$siteName = 'PowerShellSite'
$poolName = 'DemoPool'
New-Item C:inetpubwwwroot$dirName -ItemType Directory
New-Item IIS:Sites$siteName -Bindings @{protocol="http";bindinginformation="*:80:www.firstapplication.com"} -PhysicalPath C:inetpubwwwroot$dirName
New-Item IIS:AppPools$poolName
Set-ItemProperty IIS:Sites$siteName -Name applicationPool -Value $poolName
Write-Host "All Done"

Before executing the above script, You need to make sure that your powershell is configured to run multi-line scripts. For this first check your execution policy by running the following command

[abc.xyz.net]: C:> Get-ExecutionPolicy

if the above command gives you the output of “RemoteSigned” then you are good to go for executing scripts otherwise run the following command

[abc.xyz.net]: C:> Set-ExecutionPolicy remotesigned

Save the above written script with any name, i am using siteSetup.ps1. Let execute the script

[abc.xyz.net]: C:> Invoke-Expression D:setupSite.ps1

or

[abc.xyz.net]: C:> .setupSite.ps1

Deep dive into PowerShell Remoting

Let’s dive more deepen into PowerShell remoting.

Legacy VS PowerShell Remoting

In legacy approach all the commands will execute in sequential manner that may take a huge time in many scenarios.
For example: you have 10 servers and you want to configure few setting on them remotely and then you want to deploy you application on them.
In the scenario explained above legacy approach will take a lot of time as already explained it executes your commands or scripts sequentially.
So there comes the power of PowerShell remoting where you can do all this in parallel for all 10 servers. Yeah! That’s cool.

Protocols

One other aspect that I want to share is the underline protocols used.
Legacy approach use DCOM or RPC protocols whereas PowerShell remoting use WSMan protocol.
DCOM and RPC protocol are designed in the era where the firewall concept was not well grown so these protocol were designed with not considering the firewall concept in mind that means they are not firewall friendly and if you are using these any services that uses these protocols then you need a lot of complex firewall configurations. Moreover the security in these protocols are questionable and I addition to this they may not work with cloud based environment. Keeping the above scenario in mind where you are running a long scripts on multiple server all these scripts would process locally.
Contrary to that approach powerShell uses WSMan protocol that is based on “Industrial Standard Network Protocol” and is managed by WinRM services is a firewall friendly and designed in keeping the firewall concept in mind. That mean you don’t need any kind of complex firewall configuration. They are secured and all the communication is encrypted, so no packet sniffing using any tool like wireshark. They connect over a single port that is 5985 but you can configure SSL over 5986 and uses Kerberos authentication. In addition to this they are ideal for cloud environment and they process the scripts remotely. They connect to a defined endpoints where service listens to incoming connection and the endpoint passes the control to the defined application (PowerShell). PowerShell needs admin privileges for managing all the stuff you are doing remotely.

PSSessions

PSSession are used to make a connection between 2 machines. These sessions are maintained at the remote end with powerShell runspace for running cmdlets functions and scripts.
There are many types of PSSessions

  • Interactive PSSessions
  • Disconnected PSSessions

Enabling PSRemoting

To configure remoting you need to start the service named WinRM and discussed above. So we will configure WinRM to auto start. To do that use

[abc.xyz.net]: C:> Start WinRM

Then to enable remoting use

[abc.xyz.net]: C:> Enable-PSRemoting –Force

To test the connectivity and WinRM is running use

[abc.xyz.net]: C:> Test-WSMan 

You may need to restart the machine to properly pick the configuration, for that use

[abc.xyz.net]: C:> Restart-Computer computername.net –Force –Wait WinRM –Credentials

The above command will wait for the WinRM service to start and then will show its status
To disable remoting use

[abc.xyz.net]: C:> Disable-PSRemoting 

One-TO-One Remoting

One to one remoting is the case where you have only one server that you want to connect with and want to do some actions. For that lets have an interactive session with the server.

[abc.xyz.net]:  C:> Enter-PSSession –ComputerName comutername.net –Credential username –UseSSL

This will prompt the dialogue where you will enter your password to connect.
Now we are connected with the server remotely with interactive session. All the command that you execute are processed remotely and only return the result in de serialized XML objects.
To check the user session use

[abc.xyz.net]:  C:> Get-Process wsmprovhost –IncludeUserName | Select Username, startime

To get Installed Windows Features on Server use

[abc.xyz.net]:  C:> Get-WindowsFeature web* | where installed

To getting Running Windows Services use

[abc.xyz.net]:  C:> Get-Service | Where { $_.status –eq ‘Running’ }

To get specific Service use

[abc.xyz.net]:  C:> gsv WinRM

To getting installed Modules use

[abc.xyz.net]:  C:> Get-Module web* -List

To get all process use

[abc.xyz.net]:  C:> Get-Process

To filter the process result use

[abc.xyz.net]:  C:> Get-Process | sort WS –Descending | Select –First 5

PSSession

As mentioned above the Enter-PSSession is an interactive session that we have used above to connect to server. But there are also other kind of sessions. lets discuss them

New-PSSession

Using this we can save the session in a variable to use that in future and connect to it whenever we want to

PS C:> $s = New-PSSession -ComputerName abc.xyz.net -Credential username -UseSSL

Now you can connect to this session whenever you need to like

PS C:> Enter-PSSession -Session $s 

In this approach the command

[abc.xyz.net]:  C:> Exit

cannot remove the session.
You can also execute scripts and command using this session variable like

[abc.xyz.net]:  C:> icm -ScriptBlock { $p = Get-Process | Sort WS -Descending } -Session $s 

and print them in other script because the scope of variable $p is stick to the Session variable now that is $s in this case. these variables are created on the remote site. So if you want to use $p locally or in other session other then $s you cannot get it because $p is only created on one server yet.
SO ultimately that mean you can use the variable created before in future commands like below we are printing the result from the variable that we created in previous command

[abc.xyz.net]: C:> icm -ScriptBlock { $p[0..4] } -Session $s 

The above command is not possible without “-Session $s” because $p only exist in the $s session

You can get deserialized XML or version of Process from server by using

PS C:> icm -ScriptBlock { $p[0] } -Session $s | Get-Member 

Removing Session

To remove this offline kind of session use

PS C:> Remove-PSSession -Session $s 

One to Many Remoting

Fanning out

To connect with many server form one machine is knows as “Fanning out”.
Lets take an example that we have all server names in a text file, Lets read them

$computer = get-content D:computers.txt | New-PSSession –Credential username

Now you have all the server names in a variable $computer.
Lets now execute a script in all servers.

PS C:> Invoke-Command –ScriptBlock {get-service wuauserv } –Session $computer

The above command will take the sessions from $computer variable and execute the script/command on each of the server. or you can pick a script from local drive and execute it on all servers

PS C:> Invoke-Command –filepath D:script.ps1 –Session $computer

One thing to remember that you can use/pass local variable to server as demonstrated below

PS C:> $log = 'System' 
PS C:> icm { Get-EventLog $using:log -Newest 5 } –ComputerName $computer

Or pass by creating function and passing parameter

PS C:> $sb = {param($log, $count) Get-EventLog $log -Newest $count} 

here $sb is the function that we have defined that takes two arguments, lets call it

PS C:> icm $sb -ArgumentList "System", 3 

Background Jobs

If there are some scripts that takes time and you have like 10 servers, so you prefer to use the background jobs to do the task

PS C:> icm { Get-HotFix } -Session $computer -AsJob | tee -Variable hot 

In above statement we are executing a command “Get-HotFix” as a Job defined by “-AsJob” and passing its output in variable named “hot”. once the execution is done we can fetch result from this variable, lets check the status of that Job

 PS C:> $hot 

or

PS C:> $hot.childjobs  

We canalso wait from the specific job to complete by using

PS C:> Wait-Job $hot 

lets receive data from that job

PS C:> $result = Receive-Job $hot -Keep 
PS C:> $result.count 

The function that we have created before named “$sb” run locally, lets redefine the function and run it remotely as a Job

PS C:> $sb = { Start-Job { Get-EventLog system -EntryType Error } -Name SysErr }

We have defined the function as a Job and named it “SysErr”, lets execute it

PS C:> icm $sb -Session $computer

When you get the status of this job. you should get same ids on all servers because this is not running on servers. By running locally you will get unique id’s for all server and that is obvious. To get status of this job use its name

PS C:> icm { get-job SysErr } -Session $all 

You can measure the command execution time using

PS C:> Measure-Command { Get-Service }

Removing all PSSessions

To remove all alive sessions use

PS C:> Get-PSSession | Remove-PSSession 

Adding Server as a Trusted Host

PS C:> $cred = Get-Credential abc.xyz.net 

PS C:> Get-Item wsman:localhostclienttrustedhosts 

PS C:> Set-Item wsman:localhostclienttrustedhosts -Value abc* -Concatenate 

PS C:> test-wsman codingbots.cloudapp.net -Authentication Default -Credential $cred 

2nd Hope Problem

If you are on server A and creates a PSSession to connect to server B. That is the first hope. Moving further if you want to connect to Server C from Server B that will be your 2nd hope and that says “Operation failed”. This is because powershell do not allow server B to delegate your credentials to other machines. But you can enable it using the following configuration.

PS C:> icm { Get-WSManCredSSP } -computername c
PS C:> enable-wsmancredssp -Role Client -DelegateComputer server2 

It is considered as a besk practice to disable multi hoping whenever you are done with your tasks. To do so, use

PS C:> Disable-WSManCredSSP -Role Client 
PS C:>  icm { Disable-WSManCredSSP -Role Client } -computer abc.xyz.net 

That is it from my side. I hope you have enjoyed stepping into the world of Windows PowerShell.
Feel free to contact.

Happy Coding 🙂

Danyal MalikPowerShell -From Noob to Ninja
Share this post

Join the conversation