Browsing:

Month: July 2015

How to use Powershell without Google

Here are a few tips to use Powershell without using Google.

I know my way around Powershell quite OK. But I Googled a lot and when in a hurry I copied and pasted a lot. So I never took the time to be really in depth. Now is the time! And there is a way to write Powershell without Google! You need to know some very basics and how to study cmndlets, methods and properties.

Let's go!

Suppose you want to check if there are any PST's on a harddrive and let's pretend you know nothing, just like John Snow.

Find out what cmdlets are available with Get-Command

Obviously we need to recurse directories to see if there are any files with a .pst extension. So let's see if there's a cmdlet (a function) with 'dir' in it.

PS C:\Users\Jacqueline> get-command '*dir*'

CommandType     Name                         
-----------     ----
Alias           chdir -> Set-Location
Alias           dir -> Get-ChildItem
Alias           rmdir -> Remove-Item

Get-ChildItem looks like the cmdlet we need. Let's see how it works with the help files.

Get the help files

The problem with command line interfaces: you can't 'guess' which command to use and what the parameters are. So you will need to read the help files. And you will want to update them. Unfortunately, the help files are in c:\windows\system32, so you need to run the command as an Administrator. You can only update-help once a day unless you use the -Force parameter. So open a console as an Admin and run:

PS C:\> update-help -UICulture en-US -force

Needless to say an Internet connection is required. What if you don't have one?

 

Saving help to an alternate location

In that case you can save the help files on an alternate location or on a netwerk share and then update-help.

PS C:\> save-help -DestinationPath C:\powershell\help2 -force -UICulture en-US

and then (as an Administrator):

PS C:\> Update-Help -SourcePath C:\powershell\help2\ -force -UICulture en-US

Now you can use the help files.

Using the help

PS C:\> Help Get-ChildItem

Will display all there is to know about Get-Childitem. Like parameters and what kind of parameters it accepts (string, arrays and so on). If you scroll down the help you get to see the remarks:

REMARKS
    To see the examples, type: "get-help Get-ChildItem -examples".
    For more information, type: "get-help Get-ChildItem -detailed".
    For technical information, type: "get-help Get-ChildItem -full".
    For online help, type: "get-help Get-ChildItem -online"

The -examples are very convenient if you want to have a quick solution.

So now we can play a bit with Get-ChildItem. Let's discover its syntax:

SYNTAX
    Get-ChildItem [[-Path] ] [[-Filter] ] [-Exclude ] [-Force] [-Include ] [-Name] [-Recurse] [-UseTransaction
    []] []

    Get-ChildItem [[-Filter] ] [-Exclude ] [-Force] [-Include ] [-Name] [-Recurse] -LiteralPath  [-UseTransacti
    on []] []

    Get-ChildItem [-Attributes ] [-Directory] [-File] [-Force] [-Hidden] [-ReadOnly] [-System] [-UseTransaction] [
    ]

Here we see it accepts a -Path parameter which is an array because there are brackets: String[]. So we can input multiple search locations by creating an array of locations. Let's see how we can define an array in Powershell.

get-help array

And you will see you get very valuable information about how to create an array. I could create an array like this:

$search = @($env:HOMEPATH,"c:\temp")

Notice the quotes around c:\temp because we're dealing with strings.
The $env:HOMEPATH is already a variable which returns a string.

We can test the array like follows:

PS C:\Users\Jacqueline> $search = @($env:HOMEPATH\Dropbox,"c:\temp")
PS C:\Users\Jacqueline> $search
\Users\Jacqueline\Dropbox
c:\temp

Now we can do a search ilke this:

get-childitem -path $search -Recurse -Include "*.pst" 

I don't want to look at all those red error messages, so let's suppress them:

get-childitem -path $search -Recurse -Include "*.pst" -ErrorAction silentlycontinue

And now for real:

PS C:\Temp> get-childitem -path $search -Recurse -Include "*.pst" -ErrorAction SilentlyContinue

    Directory: C:\Users\Jacqueline\Dropbox\work


Mode                LastWriteTime         Length Name
----                -------------         ------ ----
-a----         5-4-2013     18:33      211305472 jacqueline.pst


    Directory: C:\temp


Mode                LastWriteTime         Length Name
----                -------------         ------ ----
-a----        26-7-2015     13:12        5242880 archive.pst
-a----        26-7-2015     13:12        5242880 old.pst

Let's put the result in a variable, like so:

$pst = Get-ChildItem -Path "c:\" -Include "*.pst" -Recurse -ErrorAction SilentlyContinue

Investigating $pst with Get-Member

Like Get-Command and Get-Help, Get-Member is a really import cmdlet you should know about. With Get-Member we can investigate which properties and methods are available. How can I actually write a script or type a command-line command without having to memorize every object model found on MSDN?

Once you connect to an object you can pipe that object to Get-Member; in turn, Get-Member will enumerate the properties and methods of that object.

PS C:\Temp> $pst | Get-Member

   TypeName: System.IO.FileInfo

Name                      MemberType     Definition
----                      ----------     ----------
Mode                      CodeProperty   System.String Mode{get=Mode;}
AppendText                Method         System.IO.StreamWriter AppendText()
CopyTo                    Method         System.IO.FileInfo CopyTo(string destFileName), System.IO.FileInfo... Create                    Method         System.IO.FileStream Create()
CreateObjRef              Method         System.Runtime.Remoting.ObjRef CreateObjRef(type requestedType)
CreateText                Method         System.IO.StreamWriter CreateText()
Decrypt                   Method         void Decrypt()
Delete                    Method         void Delete()
Encrypt                   Method         void Encrypt()
Equals                    Method         bool Equals(System.Object obj)

--MORE--

Scrolling down the list you will notice a Method GetType. Let's run that:

PS C:\Temp> $pst.GetType()

IsPublic IsSerial Name          BaseType
-------- -------- ----          --------
True     True     Object[]      System.Array

So $pst is an Array (we already knew that..) but what is in the array?

PS C:\Temp> $pst | ForEach-Object { write-host $_.GetType()}
System.IO.FileInfo
System.IO.FileInfo
System.IO.FileInfo
System.IO.FileInfo

So, we've got an array full of FileInfo objects. Each objects has a set of methods and properties, which we can query by using Get-Member.

Copying and renaming the PST's to another location

Let's copy the PST's to another location and rename then so some admin can import the PST into a mailbox.

Just copying is not that hard:

$pst | Copy-Item -Destination C:\Temp\pst-share

But if I want to rename the file as well I have to be a bit more 'developerish':

foreach ($f in $pst) {
    $name = $env:USERNAME + '-' + $f.Name
    Copy-Item $f.FullName -Destination "C:\temp\pst-share\$name"
  }

Let's debate on this script tomorrow.


Powershell Desired State Configuration simple example

While still in 'Devop Mood', let's quickly figure out Desired State Configuration.

This image gives a nice overview of the DSC architecture:

Requirements

If you have a Windows 2012 R2 Server with the latest updates and KB2883200 installed, you're good to go. Check it like so:
wmic qfe | find "KB2883200"

What Powershell Modules are there installed anyway? Go ahead, open a Powershell console and type <strong>$env:PSModulePath -split ";"</strong>
This displays the locations on your PC where there are Powershell modules installed.

PS C:\Users\vagrant> $env:PSModulePath -split ";"
C:\Users\vagrant\Documents\WindowsPowerShell\Modules
C:\Program Files\WindowsPowerShell\Modules
C:\Windows\system32\WindowsPowerShell\v1.0\Modules\

Now if you cd into C:\Windows\system32\WindowsPowerShell\v1.0\Modules\ you get to see all the modules. If all is well, one of them is PSDesiredStateConfiguration. This is where the DSC commandlets are hidden.

Resources

A resource is an 'object' which you can configure with DSC. There are 3 sources for resources.

Out of the box resources
Out of the box with Powershell v4, there are modules for File, Registry, Services etcetera. To see the complete list, do:

PS C:\> Get-DscResource | select name

This outputs:

Name
----
File
Archive
Environment
Group
Log
Package
Registry
Script
Service
User
WindowsFeature
WindowsProcess

Community resources
The Powershell community has also written some modules for DSC resources, like DNS, Active Directory and Hyper-V. You can find them here and they are prefixed with a c.

Experimental resources
The Powershell team itself also provides some experimental resources which you can find here. These resources are prefixed with an x.

You can download these resources and add them to the $env.PSModulePath folder. Which is in my case: C:\Windows\system32\WindowsPowerShell\v1.0\Modules\.

Create your first configuration

These steps describe the DSC process:

  • Add the required DSC resources
  • Create a configuration script
  • Execute the script to generate a MOF file
  • Apply the MOF to the target nodes

Now let's start with adding a folder named "c:\Replica" on every node. That means we could use the File resource, which comes out of the box. Now, how to use this file resource? Luckily, the Powershell folks have made things very easy for us. We can just type get-dscresource File -syntax and lo and behold:

PS C:\> Get-DscResource File -Syntax
File [string] #ResourceName
{
    DestinationPath = [string]
    [ Attributes = [string[]] { Archive | Hidden | ReadOnly | System }  ]
    [ Checksum = [string] { CreatedDate | ModifiedDate | SHA-1 | SHA-256 | SHA-512 }  ]
    [ Contents = [string] ]
    [ Credential = [PSCredential] ]
    [ DependsOn = [string[]] ]
    [ Ensure = [string] { Absent | Present }  ]
    [ Force = [bool] ]
    [ MatchSource = [bool] ]
    [ Recurse = [bool] ]
    [ SourcePath = [string] ]
    [ Type = [string] { Directory | File }  ]
}

So this basically explains how to use the File resource.

Fire up Powershell ISE and start type:

Configuration MyFirstConfig {

Node DSC1 {
    
    File SyncDir {
        DestinationPath = "c:\replica"
        Type = "Directory" 
        Ensure = "Present"   
    }
  }
}

MyFirstConfig -OutputPath c:\DSC

If you execute this script a MOF file will be created in c:\DSC.

Apply the MOF

Now go ahead and type: Start-DscConfiguration -Path c:\DSC

This will output:

PS C:\Windows\System32\WindowsPowerShell\v1.0\Modules> Start-DscConfiguration -Path c:\DSC

Id     Name            PSJobTypeName   State         HasMoreData     Location             Command
--     ----            -------------   -----         -----------     --------             -------
8      Job8            Configuratio... Running       True            DSC1                 Start-DscConfiguration...

And if all is well there is indeed a folder named 'replica' on your C:\ drive.

Conclusion

This was a very simple example of Powershell DSC. I think it is quite nice and I am planning to explore its possibilities in the near future (like tomorrow or so).

 
 
 


Quickly build a Windows lab with VirtualBox, Packer, Vagrant and Chocolatey

logos

I'm preparing a Powershell training for work and I needed an easy lab with virtual machines which I can easily distribute among the students. It should obviously all be Windows based.

So I started out working with Windows 10 and Vagrant to create a virtual lab, as I did on my Mac and Ubuntu box before, and I am very happy and (surprised) to announce that it works very smoothly on Windows. And I used Packer to create a Windows base box for Vagrant.

So I had great fun setting up my training lab and it would be a shame to keep it all for myself. So here goes. The Buttonfactory goes Devops!

Install Windows 10 Technical Preview and Chocolatey

Unfortunately, the preview of Windows 10 is not available anymore. If you look hard enough, I think it is possible to grab an iso somewhere.
By the way, the rest of these directions work also under Windows 7, 8 and 8.1.

screen1

Install Chocolatey
After installing Windows 10 I would advise to install Chocolatey. Chocolatey is like Ninite on the command line (or like apt-get for Windows if you will) and it is going te be very important in the future.

Open a command prompt as Administrator and paste this command in your terminal:

@powershell -NoProfile -ExecutionPolicy Bypass -Command "iex ((new-object net.webclient).DownloadString('https://chocolatey.org/install.ps1'))" && SET PATH=%PATH%;%ALLUSERSPROFILE%\chocolatey\bin

(Or just head over to https://chocolatey.org/ and follow the installation instructions).

 

Install Cmder
Then the first thing todo is install Cmder, a perfect replacement for the Windows terminal (which sucks a bit).
Fire up the command prompt as an admin and type:

//
cinst cmder -y
//

The Cmder binaries are installed in c:\tools. It is added to the path so you can just fire it up (start, run) and type Cmder.
Cmder also incorporates Msysgit which brings you, apart from Git, a light set of GNU tools as well like ls, grep, awk and vim, which I adore.

You can add another tab with a new console and tick 'Run as administrator' for convenience.
2015-07-19 14_17_18-ConEmu

 

 

 

 

And you can designate a tab for Powershell as well:
2015-07-19 14_19_59-Cmder

 

 

 

 

 

 

Install VirtualBox, Vagrant and Packer

This is also possible from Chocolatey.

//
cinst virtualbox vagrant -y
//

Add vagrant to the path. My path looks like this: C:\tools\cmder;C:\PROGRA~2\Oracle\VirtualBox;c:\HashiCorp\Vagrant\bin

The next steps to install Packer are:

  • Open Cmder
  • Type: mkdir \Vagrant
  • Type: cd \Vagrant
  • Type: git clone https://github.com/joefitzgerald/packer-windows.git
  • Cd into packer-windows and see what has been downloaded
  • Now download packer and extract all contents to the packer-windows folder. (I think that is convenient)

Build a Windows Server 2012 R2 base box

This paragraph is based on this blog post from Rui Lopes.

We are going to edit the windows_2012_r2.json a bit to adjust it to our needs:

  • On line 38: set headless to false to see what is going on
  • On line 42: change the ssh_wait_timeout from 4h to 8h (to have enough time to install all updates)
  • On line 76: Remove the ./scripts/compact.bat (it takes ages to run) and the ./scripts/chef.bat (we are not gonna need it) lines.
  • You might want to change the answer file to change the Culture, but that can be done in the Vagrantfile later.

Now we are ready to build the box. Make sure you are in the c:\vagrant\packer-windows folder and type:

//
packer build -only virtualbox-iso windows_2012_r2.json
//

And now we wait. This takes forever. I'd suggest you go for a walk or perhaps to bed early. But the price is big!

Add the Windows Server 2012 R2 base box to Vagrant

When you return from your other extra curricular activity, you will see a box file is created in the c:\vagrant\packer\packer-windows folder.
You should add this box to Vagrant:

//
vagrant box add --name windows_2012_r2 windows_2012_r2_virtualbox.box
//

This will also take a short time.

It will add the box to C:\Users\\.vagrant.d\boxes\windows_2012_r2\0\virtualbox:

2015-07-19 15_27_06-Cmder

You can basically get rid of the box file in c:\vagrant\packer\packer-windows now, or copy it to an USB drive or so because for now it is not longer needed.

Fire up the Virtual Server already!

  • Go to c:\Vagrant and create a dir for the server (mine is called DSC1)
  • cd into DSC1
  • Type vagrant init
  • Edit the Vagrantfile that this creates and make it to look like so:
    Vagrant.require_version ">= 1.6.2"
    
    $root_provision_script = <<'ROOT_PROVISION_SCRIPT'
    & $env:windir\system32\tzutil /s "W. Europe Standard Time"
    ROOT_PROVISION_SCRIPT
    
    Vagrant.configure("2") do |config|
        config.vm.define "DSC1"
        config.vm.box = "windows_2012_r2"
        config.vm.hostname = "DSC1"
    
    
        config.vm.provider :virtualbox do |v, override|
            v.gui = true
            v.customize ["modifyvm", :id, "--memory", 2048]
            v.customize ["modifyvm", :id, "--cpus", 2]
        end
    
        config.vm.network "private_network", ip: "10.10.10.4"
        config.vm.provision "shell", inline: $root_provision_script
    
    end
  • Save it
  • Type: vagrant up

When it is finished, you type vagrant rdp and you can log on to your box.
(Username vagrant, password vagrant).

2015-07-19 15_42_33-Quickly build a Windows lab with VirtualBox, Packer, Vagrant and Chocolatey _ Th

Now to halt the box: you type: vagrant halt.
To destroy the box: you type vagrant destroy.
And you can start again with a clean slate in seconds with vagrant up.

Create more folders for other servers, adjust the Vagrantfile (server name, IP address) and spin them up.

Extra: add Chocolatey to the Vagrant box

You can provision your Vagrant boxes with Chocolatey, and install Cmder and Notepad2 (or whatever packages you might need from the Choco repos). To do so, change the Vagrantfile like so:

Vagrant.require_version ">= 1.6.2"

$root_provision_script = <<'ROOT_PROVISION_SCRIPT'
#adjust the time zone:
& $env:windir\system32\tzutil /s "W. Europe Standard Time"

#install Chocolatey
iex ((new-object net.webclient).DownloadString('https://chocolatey.org/install.ps1'))

#and install Cmder and Notepad2
choco install cmder notepad2 -y
ROOT_PROVISION_SCRIPT

Vagrant.configure("2") do |config|
    config.vm.define "DSC1"
    config.vm.box = "windows_2012_r2"
	  config.vm.hostname = "DSC1"

	        config.vm.provider :virtualbox do |v, override|
		        v.gui = true
		        v.customize ["modifyvm", :id, "--memory", 2048]
		        v.customize ["modifyvm", :id, "--cpus", 2]
			    end
      config.vm.network "private_network", ip: "10.10.10.4"
      config.vm.provision "shell", inline: $root_provision_script
end