PowerShell for Windows Admins


April 1, 2017  4:31 AM

Maximum number of Acronyms

Richard Siddaway Richard Siddaway Profile: Richard Siddaway
General

IT is littered with acronyms – many of which you can’t remember what it means. This has been explained by recent research that shows there is a maximum number of acronyms that it is possible for one person to remember.

Once you’ve reached your maximum number of acronyms as soon as you try to remember a new one then one of the existing ones will be erased from you memory. The acronym to be erased seems to be selected at random though recent computer models lead researchers to suspect that its inversely proportional to your age and directly proportional to the number of different technologies you’re currently working with.

Your maximum number of acronyms seems to be hardwired on an individual basis and no amount of training seems to be able to modify this number.

If you suspect that you’re reaching your maximum number of acronyms all you can do is make sure that you have a cheat sheet available to use to look up their meaning.

Many IT vendors are actively aiding research in this area as their ability to generate incomprehensible documentation littered with acronyms is severely hindered by this new discovery.

March 31, 2017  2:23 PM

PowerShell v6

Richard Siddaway Richard Siddaway Profile: Richard Siddaway
Powershell

Tried PowerShell v6 yet?

Its the open sourced latest version of PowerShell – runs on Windows, Linux (various flavours) and MacOS

Its available from – https://github.com/PowerShell/PowerShell

Before you get too excited there’s a few things you need to remember:

– its ALPHA code. That means its still under development and subject to change

– its not production ready

– it only provides the core parts of PowerShell – for instance all the CDXML modules aren’t available

– it uses .NET Core rather than  full .NET  – it doesn’t have the GUI libraries for instance

– it does install side by side with out of the box PowerShell (on later versions of Windows only)

– it does enable remoting between Windows and Linux using SSH

Its worth testing for 2 reasons. First you can see what’s happening with PowerShell and the changes that are coming. Secondly, you can feed back directly to the project and directly influence the future of PowerShell


March 31, 2017  1:17 PM

Summit 2017–one week to go

Richard Siddaway Richard Siddaway Profile: Richard Siddaway
Powershell

With one week to go before travelling to Seattle for the 2017 PowerShell & DevOps Summit I’m putting the finishing touches to my presentations and the Summit organisation.

The agenda was published last October but we’ve had to make a few changes recently to cover for speakers that have dropped out. Check out the final version before deciding on the sessions you’ll attend.

We’ve already started planning the 2018 Summit – more details will come later – but we think you’ll like what we’re planning. All your favourite Summit features and more.

If you’re going to the Summit don’t forget to sign up for the Lightning Demos – your chance to speak and share your discoveries.


March 29, 2017  1:29 PM

Name mismatch

Richard Siddaway Richard Siddaway Profile: Richard Siddaway
Active Directory, CIM, Powershell

Ever wondered why you can’t do this:

Get-ADComputer -Filter * -SearchBase 'OU=Servers,DC=Manticore,DC=org' |
Get-CimInstance -ClassName Win32_OperatingSystem

The –ComputerName parameter on get-CimInstance accepts pipeline input BUT its by property name.

PS> Get-Help Get-CimInstance -Parameter ComputerName

-ComputerName [<String[]>]
    Specifies computer on which you want to run the CIM operation. You can specify a fully qualified domain name
    (FQDN), a NetBIOS name, or an IP address.

    If you do not specify this parameter, the cmdlet performs the operation on the local computer using Component
    Object Model (COM).

    If you specify this parameter, the cmdlet creates a temporary session to the specified computer using the WsMan
    protocol.

    If multiple operations are being performed on the same computer, using a CIM session gives better performance.

    Required?                    false
    Position?                    named
    Default value                none
    Accept pipeline input?       True (ByPropertyName)
    Accept wildcard characters?  false

If you look at the output of Get-ADComputer it has a Name property.

PS>  Get-ADComputer -Filter * -SearchBase 'OU=Servers,DC=Manticore,DC=org'

DistinguishedName : CN=W16PWA01,OU=Servers,DC=Manticore,DC=org
DNSHostName       : W16PWA01.Manticore.org
Enabled           : True
Name              : W16PWA01
ObjectClass       : computer
ObjectGUID        : 8d137004-1ced-4ff1-bcf4-f0671652fc8c
SamAccountName    : W16PWA01$
SID               : S-1-5-21-759617655-3516038109-1479587680-1322
UserPrincipalName :

So you have a Name mismatch between the property and the parameter.

There are a number of ways to deal with this.

First use foreach

Get-ADComputer -Filter * -SearchBase 'OU=Servers,DC=Manticore,DC=org' |
foreach {
  Get-CimInstance -ClassName Win32_OperatingSystem -ComputerName $psitem.Name | 
  select CSName, Caption
}

Use $psitem.Name (or $_.Name) as the input to –ComputerName. Simple coding and works very nicely.

If you have a lot of computers you may want to use a foreach loop instead

$computers = Get-ADComputer -Filter * -SearchBase 'OU=Servers,DC=Manticore,DC=org' | select -ExpandProperty Name
foreach ($computer in $computers) {
  Get-CimInstance -ClassName Win32_OperatingSystem -ComputerName $computer|
  select CSName, Caption
}

Create an array of computer names and iterate through them.

Second use select

Get-ADComputer -Filter * -SearchBase 'OU=Servers,DC=Manticore,DC=org' |
select @{N='ComputerName';E={$_.Name}} |
Get-CimInstance -ClassName Win32_OperatingSystem |
select CSName, Caption

In this case use select-object to create a property with the name ComputerName (case DOESN’T matter) and pipe that into Get-CimInstance.

This option is a bit more advanced as you have understand how select-object works and how to create extra properties on the object you’re passing down the pipeline. It looks cooler and should get you a few extra “ace powerShell coder” points.

The third option takes advantage of the fact that _Computername accepts an array of computer names

Get-CimInstance -ClassName Win32_OperatingSystem -ComputerName (Get-ADComputer -Filter * -SearchBase 'OU=Servers,DC=Manticore,DC=org' | select -ExpandProperty Name) |
select CSName, Caption

You run Get-ADComputer and use select –Expand to only return the VALUE of the computer name (a string). This gives you an array of computer names. Because its in () its treated as an input object to the parameter.

Very clever and gets you maximum points.


March 22, 2017  2:49 PM

Get-SupportedFileSystems

Richard Siddaway Richard Siddaway Profile: Richard Siddaway
CIM, Powershell

I stumbled on the Get-SupportedFileSystems cmdlet today. Its part of the Storage module and is defined as a function. Digging a bit further its from a CDXML module based on a CIM class. But which CDXML file contains the definition?

PS> Get-ChildItem -Path 'C:\Windows\System32\WindowsPowerShell\v1.0\Modules\Storage' -File | Select-String -Pattern 'Get-SupportedFileSystems' -SimpleMatch

C:\Windows\System32\WindowsPowerShell\v1.0\Modules\Storage\Storage.psd1:117:        'Get-SupportedFileSystems',
C:\Windows\System32\WindowsPowerShell\v1.0\Modules\Storage\Volume.cdxml:405:      // Get-SupportedFileSystems

Looking in Volume.cdxml shows we’re working with the ROOT/Microsoft/Windows/Storage/MSFT_Volume class. You can use this directly

PS> Get-CimInstance -Namespace ROOT/Microsoft/Windows/Storage -ClassName MSFT_Volume | select DriveLetter, FileSystem

DriveLetter FileSystem
----------- ----------
          D
            NTFS
            NTFS
          C NTFS

When you use Get-SupportedFileSystems all you get back is the filesystem

PS> Get-SupportedFileSystems -DriveLetter C
NTFS

The DriveLetter parameter can take an array of chars but if you supply a driveletter where there isn’t a defined filesystem you get an error

PS> Get-SupportedFileSystems -DriveLetter D
Get-SupportedFileSystems : Failed
Activity ID: {25bde807-4d9f-4216-8640-94268ff80624}
At line:1 char:1
+ Get-SupportedFileSystems -DriveLetter D
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : NotSpecified: (StorageWMI:ROOT/Microsoft/...age/MSFT_Volume) [Get-SupportedFileSystems],
    CimException
    + FullyQualifiedErrorId : StorageWMI 4,Get-SupportedFileSystems

or if the drive isn’t defined

PS> Get-SupportedFileSystems -DriveLetter E
Get-SupportedFileSystems : No MSFT_Volume objects found with property 'DriveLetter' equal to 'E'.  Verify the value of the property and retry.
At line:1 char:1
+ Get-SupportedFileSystems -DriveLetter E
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : ObjectNotFound: (E:Char) [Get-SupportedFileSystems], CimJobException
    + FullyQualifiedErrorId : CmdletizationQuery_NotFound_DriveLetter,Get-SupportedFileSystems

The DriveLetter parameter accepts pipeline input by propertyname BUT it has to be a Char not a string.

What would be useful would be to get the drives using Get-PSDrive and pass to Get-SupportedFileSystems

PS> Get-PSDrive -PSProvider FileSystem | Format-Table -AutoSize

Name Used (GB) Free (GB) Provider   Root CurrentLocation
---- --------- --------- --------   ---- ---------------
C       202.61    273.55 FileSystem C:\          Scripts
D                        FileSystem D:\

Get-PSDrive outputs the driveletter as the name property and just make life fun its a string.

Time for some PowerShell magic.

This looks good

Get-PSDrive -PSProvider FileSystem |
select @{N='DriveLetter'; E={[char]$_.Name}} |
Get-SupportedFileSystems

but it fails because D doesn’t have a filesystem defined.

So try this

Get-PSDrive -PSProvider FileSystem |
foreach {
  $props = [ordered]@{
    DriveLetter = $_.Name
    FileSystem = Get-SupportedFileSystems -DriveLetter $_.Name -ErrorAction SilentlyContinue
  }
  New-Object -TypeName PSObject -Property $props
}

DriveLetter FileSystem
----------- ----------
C           NTFS      
D

A simple way to check the filesystem used on your Windows machines

 

 


March 22, 2017  1:43 PM

PowerShell Summit 2017–Community Lightning Demos

Richard Siddaway Richard Siddaway Profile: Richard Siddaway
Powershell

Early Summits, and their precursors – the PowerShell Deep Dives – featured Lightning rounds where attendees had 10 minutes or so to present something PowerShell related – a tip, trick, discovery, cool piece of code, new technique etc etc etc …

Summit 2017 brings that concept back. If you’re attending Summit, and if not why not, and you want to be involved check out https://powershell.org/2017/03/22/community-lightning-demos-call-for-proposals/ and sign up.


March 20, 2017  3:10 PM

Updating built in modules

Richard Siddaway Richard Siddaway Profile: Richard Siddaway
Powershell

Windows 10 and Server 2016 automatically install a module called Pester which is used for testing code. Its the foundation of Test Driven Development or Behaviour Driven Development using PowerShell.

The version  installed by default is 3.4.0.

Pester is originally an open source module that has been incorporated into Windows. The latest version from the PowerShell Gallery is 4.0.2

Normally you’d use Update-Module to install the new version BUT you didn’t install pester from the gallery using Install-Module so you’ll get a big fat error message.

The answer is to use

Install-Module pester –Force

You might still get an error message about the Pester module not being catalog signed. if you do and still want the latest version then use

Install-Module pester -Force -SkipPublisherCheck


March 10, 2017  2:49 PM

Hyper-V book deal

Richard Siddaway Richard Siddaway Profile: Richard Siddaway
Books, Hyper-V, Powershell

March 11 2017 – My book Learn Hyper-V in a Month of Lunches is Manning’s Deal of the day. Get 50% off using code dotd031117au at http://bit.ly/2niU715

Also see https://www.manning.com/dotd


March 6, 2017  11:53 AM

Windows 10 uptime

Richard Siddaway Richard Siddaway Profile: Richard Siddaway
Powershell, Windows 10

One of the things that managers seem to be fascinated with is up time. For Windows server operating systems its a fairly simple calculation

PS>  (Get-Date) – (Get-CimInstance -ClassName Win32_OperatingSystem | select -ExpandProperty LastBootUpTime)

Days              : 0
Hours             : 3
Minutes           : 46
Seconds           : 45
Milliseconds      : 465
Ticks             : 136054659217
TotalDays         : 0.157470670390046
TotalHours        : 3.77929608936111
TotalMinutes      : 226.757765361667
TotalSeconds      : 13605.4659217
TotalMilliseconds : 13605465.9217

You can get a bit more precise by using the time the event log service is started as that’s early in the boot sequence while LastBootUpTime really records when the machine is ready to access. If you want to use the event log methodology see https://richardspowershellblog.wordpress.com/2009/02/14/machine-uptime/

With Windows 10 (actually with Windows 8 or 8.1 as well) this breaks down.

PS> (Get-Date) – (Get-CimInstance -ClassName Win32_OperatingSystem | select -ExpandProperty LastBootUpTime)

Days              : 23
Hours             : 6
Minutes           : 57
Seconds           : 55
Milliseconds      : 371
Ticks             : 20122753718697
TotalDays         : 23.2902242114549
TotalHours        : 558.965381074917
TotalMinutes      : 33537.922864495
TotalSeconds      : 2012275.3718697
TotalMilliseconds : 2012275371.8697

I use my computer a lot but 23 days is a bit excessive even for me.

If we look at the last boot time

PS> Get-CimInstance -ClassName Win32_OperatingSystem | select LastBootUpTime

LastBootUpTime
--------------
11/02/2017 10:00:35

You can see the calculation is correct.

This happens because Windows 10 (and 8 and 8.1) don’t fully power down when you do a Shut Down. They enter an extreme sleep state. This is the reason that start up times shrunk so dramatically when Windows 8 was introduced.

So how can you determine when your Windows 10, 8.1 or 8 machine was used.

You might be tempted to look in the System event log – where you’ll find entries like this each time the Windows machine is woken up

PS> Get-EventLog -LogName system -InstanceId 2147489661 | select -First 1 | Format-List


Index              : 8668
EntryType          : Information
InstanceId         : 2147489661
Message            : The system uptime is 1995412 seconds.
Category           : (0)
CategoryNumber     : 0
ReplacementStrings : {, , , ...}
Source             : EventLog
TimeGenerated      : 06/03/2017 12:17:24
TimeWritten        : 06/03/2017 12:17:24
UserName           :

Unfortunately this takes us back to out 23 days

PS> New-TimeSpan -Seconds 1995412


Days              : 23
Hours             : 2
Minutes           : 16
Seconds           : 52
Milliseconds      : 0
Ticks             : 19954120000000
TotalDays         : 23.0950462962963
TotalHours        : 554.281111111111
TotalMinutes      : 33256.8666666667
TotalSeconds      : 1995412
TotalMilliseconds : 1995412000

Using the event log service start up also gives us the hard power up date

PS> Get-EventLog -LogName system | where{(($_.EventId -eq 6005) -or ($_.EventId -eq 6006)) } | select -First 1 | Format-
List


Index              : 6275
EntryType          : Information
InstanceId         : 2147489653
Message            : The Event log service was started.
Category           : (0)
CategoryNumber     : 0
ReplacementStrings : {}
Source             : EventLog
TimeGenerated      : 11/02/2017 10:00:30
TimeWritten        : 11/02/2017 10:00:30
UserName           :

There is an entry in the System event log for when the machine comes out of its power down mode:

PS> Get-EventLog -LogName system -InstanceId 1 | where Message -Like '*low power*' | select -First 1 | Format-List


Index              : 8683
EntryType          : Information
InstanceId         : 1
Message            : The system has returned from a low power state.

                     Sleep Time: 2017-03-05T22:00:54.261033400Z
                     Wake Time: 2017-03-06T12:17:26.089189400Z

                     Wake Source: 0
Category           : (0)
CategoryNumber     : 0
ReplacementStrings : {2017-03-05T22:00:54.261033400Z, 2017-03-06T12:17:26.089189400Z, 1245, 1590...}
Source             : Microsoft-Windows-Power-Troubleshooter
TimeGenerated      : 06/03/2017 12:17:28
TimeWritten        : 06/03/2017 12:17:28
UserName           : NT AUTHORITY\LOCAL SERVICE

so you could calculate uptime as

PS> (Get-Date) - (Get-EventLog -LogName system -InstanceId 1 | where Message -Like '*low power*' | select -First 1 | sel
ect -ExpandProperty TimeGenerated)


Days              : 0
Hours             : 4
Minutes           : 54
Seconds           : 9
Milliseconds      : 174
Ticks             : 176491748155
TotalDays         : 0.20427285666088
TotalHours        : 4.90254855986111
TotalMinutes      : 294.152913591667
TotalSeconds      : 17649.1748155
TotalMilliseconds : 17649174.8155

If you really wanted to you could dig into the log entries and use the sleep and wake times in the message block

PS> Get-EventLog -LogName system -InstanceId 1 | where Message -Like '*low power*' | select -First 1 | select -ExpandPro
perty ReplacementStrings
2017-03-05T22:00:54.261033400Z
2017-03-06T12:17:26.089189400Z
1245
1590
1501
0
9469
5143
195417
16641
6
5
0
0

0
0
0
PS> $rs = Get-EventLog -LogName system -InstanceId 1 | where Message -Like '*low power*' | select -First 1 | select -ExpandProperty ReplacementStrings

From which you can calculate the time the machine was powered down (asleep)

PS> [datetime]$rs[1] - [datetime]$rs[0]


Days              : 0
Hours             : 14
Minutes           : 16
Seconds           : 31
Milliseconds      : 828
Ticks             : 513918281560
TotalDays         : 0.59481282587963
TotalHours        : 14.2755078211111
TotalMinutes      : 856.530469266667
TotalSeconds      : 51391.828156
TotalMilliseconds : 51391828.156

So how much have I been using the machine in the last week

$now = Get-Date
$start = $now.AddDays(-7)

$events = Get-EventLog -LogName system -InstanceId 1 -After $start  | 
where Message -Like '*low power*'

$lastevt = $events.Count - 1 


## time since last wake up
$usetime = $now - [datetime]$events[0].ReplacementStrings[1]

for ($i=0; $i -lt $lastevt; $i++){
 
  $Sleep = [datetime]$events[$i].ReplacementStrings[0]
  $Wake = [datetime]$events[$i+1].ReplacementStrings[1]
  
  $tt = $sleep - $wake

  $usetime += $tt

}

$usetime
Days              : 2
Hours             : 15
Minutes           : 46
Seconds           : 20
Milliseconds      : 736
Ticks             : 2295807363007
TotalDays         : 2.65718444792477
TotalHours        : 63.7724267501944
TotalMinutes      : 3826.34560501167
TotalSeconds      : 229580.7363007
TotalMilliseconds : 229580736.3007

Calculating Windows 10 uptime isn’t simple but can be done with these techniques


March 4, 2017  10:31 AM

Full Summit agenda available

Richard Siddaway Richard Siddaway Profile: Richard Siddaway
Powershell

The full agenda – including the PowerShell team sessions – is now available on the event web site – – https://eventloom.com/event/home/summit2017

This is our biggest ever Summit. We’ve sold out for this year and are already making plans for next year’s Summit. Look for more information later in the year.


Forgot Password

No problem! Submit your e-mail address below. We'll send you an e-mail containing your password.

Your password has been sent to: