PowerShell for Windows Admins


September 24, 2012  12:10 PM

WMI over WSMAN

Richard Siddaway Richard Siddaway Profile: Richard Siddaway

Every time I look at PowerShell v3 I seem to find a new way to access WMI!

I’ve covered the –ComputerName and –CimSession parameters before but to recap

We duplicate the way Get-WmiObject works:

$computer = $env:COMPUTERNAME
Get-CimInstance -ClassName Win32_OperatingSystem -ComputerName $computer

 

We can use CIM sessions
$cs = New-CimSession -ComputerName $computer
Get-CimInstance -ClassName Win32_OperatingSystem -CimSession $cs

 

One little known and little used capability in PowerShell v2 was the WSMAN cmdlets. These enable us to access WMI directly over WSMAN

$ruri = "http://schemas.microsoft.com/wbem/wsman/1/wmi/root/cimv2/Win32_OperatingSystem"
Get-WSManInstance -ResourceURI $ruri -ComputerName $computer

This is fine for a single returned instance but where there are multiples eg disks we need to do a bit more work

$ruri = http://schemas.microsoft.com/wbem/wsman/1/wmi/root/cimv2/Win32_LogicalDisk

Get-WSManInstance -ResourceURI $ruri -ComputerName $computer -Enumerate |
select DeviceId, Description

It turns out that we can use these ResourceURIs with Get-CimInstance

$ruri = http://schemas.microsoft.com/wbem/wsman/1/wmi/root/cimv2/Win32_OperatingSystem

Get-CimInstance -ResourceUri $ruri -ComputerName $computer
Get-CimInstance -ResourceUri $ruri -CimSession $cs

Better still if we are going after multiple instances

$ruri = "http://schemas.microsoft.com/wbem/wsman/1/wmi/root/cimv2/Win32_LogicalDisk"
Get-CimInstance -ResourceUri $ruri -ComputerName $computer |
select DeviceId, Description

Get-CimInstance -ResourceUri $ruri -CimSession $cs |
select DeviceId, Description

You have to use –ComputerName OR –CimSession if you use –ResourceURI.  If you don’t you make a DCOM connection to the local machine and you request will fail. You also won’t be able to use –ResourceURI if your CIM session is over DCOM

September 23, 2012  9:40 AM

PowerShell remoting and upgrading to Windows 2012

Richard Siddaway Richard Siddaway Profile: Richard Siddaway

I have a number of  virtual machines running Windows 2008 R2 and I upgraded one of them to Windows 2012 – an over the top upgrade rather than a format and clean install

I found that Get-PSSession –Computername didn’t work against that machine.

This parameter now looks at the remote machine endpoint and gets all remoting sessions connected to the machine. I verified that the command worked correctly against a clean install of Windows 2012. This pointed to a WSMAN configuration issue.

I found two issues:

  • PSversion remained on 2.0 after the upgrade
  • SDKversion remained on 1 after the upgrade

You can’t just do a blanket upgrade on SDKversion because some of the endpoints remain on 1 even in a clean Windows 2012 install.

This is what I ended up doing:

Set-Item -Path wsman:\localhost\plugin\microsoft.powershell\InitializationParameters\PSVersion -Value 3.0
Set-Item -Path wsman:\localhost\plugin\microsoft.ServerManager\InitializationParameters\PSVersion -Value 3.0
Set-Item -Path wsman:\localhost\plugin\Microsoft.PowerShell32\InitializationParameters\PSVersion -Value 3.0

Set-Item -Path wsman:\localhost\plugin\Microsoft.PowerShell32\SDKVersion -Value 2
Set-Item -Path wsman:\localhost\plugin\Microsoft.PowerShell\SDKVersion -Value 2
Restart-Service winrm

That didn’t completely fix it so I restarted the remote machine then ran:

Disable-PSRemoting –Force
Enable-PSRemoting –Force

That seemed to fix the problem.

At the moment all seems to be working BUT I’ve more testing to do before I’m 100% happy with this.  This isn’t a procedure I’d recommend unless you exactly what you are doing and why.

Don’t try this at home until you are sure you need to.


September 21, 2012  1:39 PM

Scripting Games 2013

Richard Siddaway Richard Siddaway Profile: Richard Siddaway

Advanced notice that there will be a Games next year – its changing a bit though.  See http://powershell.org/games/


September 21, 2012  12:46 PM

Using –showwindow

Richard Siddaway Richard Siddaway Profile: Richard Siddaway

The new –showwindow parameter in Get-Help pops up a little window containing the FULL help file.  Much better than having to rememebr to use –full.  PowerShell immediately returns the prompt so you can continue working – means you can have a number of help files open simultaneously.

Get-Help -Name Get-Process –ShowWindow

This gets to be a bit too much typing – so time to use PowerShell to help and create a function to do the work.

function doc {            
param (            
 [string]$subject            
)            
Get-Help -Name $subject -ShowWindow            
}

pass in the subject and get the help Window.

I’ve added this to my profile for constant access


September 17, 2012  2:24 PM

Change user attribute based on group membership

Richard Siddaway Richard Siddaway Profile: Richard Siddaway

Want to change an attribute on all members of an Active Directory group.  Then try this

Get-ADGroupMember -Identity Legal |             
where {$_.objectclass -eq "user"} |            
foreach {            
 Set-ADUser -Identity $($_.distinguishedName) -Department "Student"            
}

Get the group members – filter out nested groups by checking the objectclass of the object. For each user set the attribute.

You can test its worked or look at an attribute in a similar way

Get-ADGroupMember -Identity Legal |             
where {$_.objectclass -eq "user"} |            
foreach {            
 Get-ADUser -Identity $($_.distinguishedName) -Property Department |            
 select Name, distinguishedName, Department            
}

You can perform a similar process with the Quest cmdlets


September 16, 2012  1:17 PM

Decoding the mounted device information

Richard Siddaway Richard Siddaway Profile: Richard Siddaway

In the previous post we looked at how to read the mounted device information. The data is in binary though – if you want it readable and not all of it is readable – try this

$data = @()            
Get-Item -Path HKLM:\SYSTEM\MountedDevices |            
select -ExpandProperty Property |            
where {$_ -like "\Dos*"} |             
foreach {            
 $name = $_            
 $bin = (Get-ItemProperty -Path HKLM:\SYSTEM\MountedDevices -Name $name)."$name"            
             
 $decoded = @()            
 $bin | foreach {            
  $decoded += [char]$_            
 }            
            
            
 $data += New-Object -TypeName psobject -Property @{            
  Device =  $name            
  BinaryValue  = $bin            
  DecodedValue = $($decoded -join "")            
 }            
             
}            
$data | Format-Table  Device, DecodedValue  -AutoSize

Same as last time except for the loop through the binary data using [char] to decode the ASCII values.  use –join to make a string rather than an array. The apparent gaps in the resultant string are because we’re dealing with Unicode


September 16, 2012  7:41 AM

Reading mounted device information from the registry

Richard Siddaway Richard Siddaway Profile: Richard Siddaway

Interesting question about reading the registry.  How do you read HKLM:\SYSTEM\MountedDevices and pull out the name of the device and the associated data.

Get-Item -Path HKLM:\SYSTEM\MountedDevices

returns data of this form

Name                           Property
—-                           ——–
MountedDevices                 \DosDevices\C: : {218, 187, 32, 142…}
                               \DosDevices\G: : {92, 0, 63, 0…}
                               \DosDevices\E: : {95, 0, 63, 0…}
                               \DosDevices\F: : {92, 0, 63, 0…}
                               \DosDevices\D: : {218, 187, 32, 142…}
                               \DosDevices\I: : {95, 0, 63, 0…}

We need to drill into the property but if we expand the property we will only get the name of the device. So we need to loop through those names

$data = @()            
Get-Item -Path HKLM:\SYSTEM\MountedDevices |            
select -ExpandProperty Property |            
where {$_ -like "\Dos*"} |             
foreach {            
 $name = $_            
$data += New-Object -TypeName psobject -Property @{            
  Device =  $name             
  Value  = (Get-ItemProperty -Path HKLM:\SYSTEM\MountedDevices -Name $name)."$name"            
 }            
            
}            
$data

To simplify the output is limited to Dos devices

Get-itemproperty returns the data with the name of the device as the property name so we need to drill in to get the value


September 16, 2012  7:03 AM

Random confusion

Richard Siddaway Richard Siddaway Profile: Richard Siddaway

There seems to be a bit of cofusion about how Get-Random works.

Try this

1..10 | foreach {Get-Random}

you’ll get  randomly selected 32-bit unsigned integer between 0 (zero) and Int32.MaxValue (0x7FFFFFFF, 2,147,483,647).

The –Minimum parameter sets a minimum value – you will not get any values BELOW this

try this

1..10 | foreach {Get-Random -Minimum 1000}

The –Maximum parameter sets the ceiling on returned values – you will not get any values AT OR ABOVE this value

try this

1..10 | foreach {Get-Random -Maximum 1000}

used in conjunction they define a range of values from which a random value is chosen

try this

1..10 | foreach {Get-Random -Minimum 500 -Maximum 1000}


September 12, 2012  2:26 PM

PowerShell Summit 2013 dates

Richard Siddaway Richard Siddaway Profile: Richard Siddaway

The dates for the summit have been announced – 22-24 April 2013 @ Microsoft campus Redmond

You can register at http://powershell.org/summit

1/7 th of the tickets have already gone – don’t miss out.


September 11, 2012  11:22 AM

Finding the drive letter of a mounted VHD

Richard Siddaway Richard Siddaway Profile: Richard Siddaway

In Windows 8/2012 you can mount a VHD into the file system. Is there a way to discover the drive letter of the mounted VHD

function get-mountedvhdDrive {            
$disks = Get-CimInstance -ClassName Win32_DiskDrive | where Caption -eq "Microsoft Virtual Disk"            
foreach ($disk in $disks){            
 $vols = Get-CimAssociatedInstance -CimInstance $disk -ResultClassName Win32_DiskPartition             
 foreach ($vol in $vols){            
   Get-CimAssociatedInstance -CimInstance $vol -ResultClassName Win32_LogicalDisk |            
   where VolumeName -ne 'System Reserved'            
 }            
}            
}

Use Get-CimInstance to get the Win32_DiskDrive class. Filter on caption equalling "Microsoft Virtual Disk"

for each “physical” disk returned get the associated Win32_Volume and use that to get the associated Win32_Logical disk where you will find the drive letter.

Nice example of using associations in the CIM cmdlets


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: