Monthly Archive

Categories

CDXML

DiskPart and PowerShell–part 1

An attendee at the Summit made the statement that the DiskPart utility didn’t have any equivalent in PowerShell. That’s not strictly true as the storage module provides a lot of functionality that maps to diskpart functionality.

The module contents include:

PS> Get-Command -Module Storage | select name

Name
----
Disable-PhysicalDiskIndication
Disable-StorageDiagnosticLog
Enable-PhysicalDiskIndication
Enable-StorageDiagnosticLog
Flush-Volume
Get-DiskSNV
Get-PhysicalDiskSNV
Get-StorageEnclosureSNV
Initialize-Volume
Write-FileSystemCache
Add-InitiatorIdToMaskingSet
Add-PartitionAccessPath
Add-PhysicalDisk
Add-TargetPortToMaskingSet
Add-VirtualDiskToMaskingSet
Block-FileShareAccess
Clear-Disk
Clear-FileStorageTier
Clear-StorageDiagnosticInfo
Connect-VirtualDisk
Debug-FileShare
Debug-StorageSubSystem
Debug-Volume
Disable-PhysicalDiskIdentification
Disable-StorageEnclosureIdentification
Disable-StorageHighAvailability
Disable-StorageMaintenanceMode
Disconnect-VirtualDisk
Dismount-DiskImage
Enable-PhysicalDiskIdentification
Enable-StorageEnclosureIdentification
Enable-StorageHighAvailability
Enable-StorageMaintenanceMode
Format-Volume
Get-DedupProperties
Get-Disk
Get-DiskImage
Get-DiskStorageNodeView
Get-FileIntegrity
Get-FileShare
Get-FileShareAccessControlEntry
Get-FileStorageTier
Get-InitiatorId
Get-InitiatorPort
Get-MaskingSet
Get-OffloadDataTransferSetting
Get-Partition
Get-PartitionSupportedSize
Get-PhysicalDisk
Get-PhysicalDiskStorageNodeView
Get-PhysicalExtent
Get-PhysicalExtentAssociation
Get-ResiliencySetting
Get-StorageAdvancedProperty
Get-StorageDiagnosticInfo
Get-StorageEnclosure
Get-StorageEnclosureStorageNodeView
Get-StorageEnclosureVendorData
Get-StorageFaultDomain
Get-StorageFileServer
Get-StorageFirmwareInformation
Get-StorageHealthAction
Get-StorageHealthReport
Get-StorageHealthSetting
Get-StorageJob
Get-StorageNode
Get-StoragePool
Get-StorageProvider
Get-StorageReliabilityCounter
Get-StorageSetting
Get-StorageSubSystem
Get-StorageTier
Get-StorageTierSupportedSize
Get-SupportedClusterSizes
Get-SupportedFileSystems
Get-TargetPort
Get-TargetPortal
Get-VirtualDisk
Get-VirtualDiskSupportedSize
Get-Volume
Get-VolumeCorruptionCount
Get-VolumeScrubPolicy
Grant-FileShareAccess
Hide-VirtualDisk
Initialize-Disk
Mount-DiskImage
New-FileShare
New-MaskingSet
New-Partition
New-StorageFileServer
New-StoragePool
New-StorageSubsystemVirtualDisk
New-StorageTier
New-VirtualDisk
New-VirtualDiskClone
New-VirtualDiskSnapshot
New-Volume
Optimize-StoragePool
Optimize-Volume
Register-StorageSubsystem
Remove-FileShare
Remove-InitiatorId
Remove-InitiatorIdFromMaskingSet
Remove-MaskingSet
Remove-Partition
Remove-PartitionAccessPath
Remove-PhysicalDisk
Remove-StorageFileServer
Remove-StorageHealthSetting
Remove-StoragePool
Remove-StorageTier
Remove-TargetPortFromMaskingSet
Remove-VirtualDisk
Remove-VirtualDiskFromMaskingSet
Rename-MaskingSet
Repair-FileIntegrity
Repair-VirtualDisk
Repair-Volume
Reset-PhysicalDisk
Reset-StorageReliabilityCounter
Resize-Partition
Resize-StorageTier
Resize-VirtualDisk
Revoke-FileShareAccess
Set-Disk
Set-FileIntegrity
Set-FileShare
Set-FileStorageTier
Set-InitiatorPort
Set-Partition
Set-PhysicalDisk
Set-ResiliencySetting
Set-StorageFileServer
Set-StorageHealthSetting
Set-StoragePool
Set-StorageProvider
Set-StorageSetting
Set-StorageSubSystem
Set-StorageTier
Set-VirtualDisk
Set-Volume
Set-VolumeScrubPolicy
Show-VirtualDisk
Start-StorageDiagnosticLog
Stop-StorageDiagnosticLog
Stop-StorageJob
Unblock-FileShareAccess
Unregister-StorageSubsystem
Update-Disk
Update-HostStorageCache
Update-StorageFirmware
Update-StoragePool
Update-StorageProviderCache
Write-VolumeCache

In this mini series I’m going to go through a number of the diskpart options and show you how to do the same with the Storage module cmdlets.

I’m not sure if all diskpart options are available but it’ll be fun to find out.

The Storage module was introduced with Windows 8/Server 2012.

ls $pshome\modules\storage

or

Get-ChildItem $pshome\modules\storage

if you prefer shows a number of cdxml files. This means that the cmdlets are based on CIM classes which you can see at

Get-CimClass -Namespace ROOT/Microsoft/Windows/Storage

These classes aren’t available on versions of Windows prior to Windows 8/Server 2012.

I’ll also have a look at some of these classes to see if there’s anything we can do that isn’t covered directly by the storage module cmdlets.

WMF 5.0 April 2015 preview – – software inventory logging

A software inventory module is now included with the April 2015 WMF 5.0 preview

£> Get-Command -Module SoftwareInventoryLogging | select Name

Name
----
Get-SilComputer
Get-SilComputerIdentity
Get-SilData
Get-SilLogging
Get-SilSoftware
Get-SilUalAccess
Get-SilWindowsUpdate
Publish-SilData
Set-SilLogging
Start-SilLogging
Stop-SilLogging

 

Windows updates are always a good place to start poking into your systems

£> Get-Command Get-SilWindowsUpdate -Syntax

Get-SilWindowsUpdate [[-ID] <string[]>] [-CimSession <CimSession[]>]
[-ThrottleLimit <int>] [-AsJob] [<CommonParameters>]

£> Get-SilWindowsUpdate

ID          : KB3055381
InstallDate : 4/30/2015

etc

 

The parameters for Get-SilWindowsUpdate look like those I’d expect from a CDXML module. Inspection of C:\Windows\System32\WindowsPowerShell\v1.0\modules\SoftwareInventoryLogging\

shows  a number of cdxml files

MsftSil_Computer.cdxml
MsftSil_ComputerIdentity.cdxml
MsftSil_Data.cdxml
MsftSil_ManagementTasks.psm1
MsftSil_Software.cdxml
MsftSil_UalAccess.cdxml
MsftSil_WindowsUpdate.cdxml
Msft_MiStreamTasks.cdxml

 

The WMF 5,0 release notes supply a link to further data of software inventory logging – interestingly its flagged as a Windows Server 2012 R2 page.

Trying the cmdlet against a Windows Server 2012 R2 system running WMF 4.0 (with the November 2014 roll up)

$cs = New-CimSession -ComputerName W12R2SUS
Get-SilWindowsUpdate -CimSession $cs

£> Get-SilWindowsUpdate -CimSession $cs

ID             : KB3006193
InstallDate    : 1/5/2015
PSComputerName : W12R2SUS

etc

 

This means the class is on our Windows Server 2012 R2 box so we could use it directly

£> Get-CimInstance -Namespace root/InventoryLogging -ClassName  MsftSil_WindowsUpdate | Format-Table -a

ID                  InstallDate                                PSComputerName
--                   -----------                                 --------------
KB3006193 1/5/2015 12:00:00 AM
KB2894856 9/14/2014 12:00:00 AM

etc

 

This module supplies a useful way to find out the software installed on our systems – I’ll be digging into this over a few more posts

Scripting Guy CDXML series finished

My CDXML series on the Scripting Guy blog finished today.  The 4 articles are:

 

http://blogs.technet.com/b/heyscriptingguy/archive/2015/02/02/registry-cmdlets-manage-the-registry.aspx

 

http://blogs.technet.com/b/heyscriptingguy/archive/2015/02/03/registry-cmdlets-first-steps-with-cdxml.aspx

 

http://blogs.technet.com/b/heyscriptingguy/archive/2015/02/04/registry-cmdlets-advanced-cdxml.aspx

 

http://blogs.technet.com/b/heyscriptingguy/archive/2015/02/05/registry-cmdlets-using-advanced-cdxml.aspx

Scripting Guy CDXML series

Today starts a four part series I’ve written for the Scripting Guy blog on using CDXML to create a module to work with the registry.  Don’t know what CDXML is – you will when you’ve read the series

 

The first post is at http://blogs.technet.com/b/heyscriptingguy/archive/2015/02/02/registry-cmdlets-manage-the-registry.aspx

CDXML: Cim jobs

One of the freebies you get when using CDXML is that the cmdlets you create automatically get the –AsJob parameter. I was thinking about jobs in general and realised that I didn’t know how CIM jobs were run.

To put this into context:

PowerShell jobs run in another PowerShell process that is started as a child of the PowerShell process in which you start the job.

WMI jobs use a process called unsecapp - C:\Windows\System32\wbem\unsecapp

Another process - C:\Windows\system32\wbem\wmiprvse.exe will also run.

 

In order to discover the process(es) used by CIM jobs I needed a CIM job that would run for a long time – using CIM_DataFile class to enumerate the files on disk would work. I created a quick module using that class

<?xml version='1.0' encoding='utf-8'?>
<PowerShellMetadata xmlns='http://schemas.microsoft.com/cmdlets-over-objects/2009/11'>
  <Class ClassName='ROOT\cimv2\Cim_DataFile'>
    <Version>1.0</Version>
    <DefaultNoun>DataFile</DefaultNoun>

    <InstanceCmdlets>
      <GetCmdletParameters DefaultCmdletParameterSet='DefaultSet'>
             
      </GetCmdletParameters>
    </InstanceCmdlets> 
  </Class>
 
</PowerShellMetadata>

 

and saved it as Cim_DataFile.cdxml

 

After importing the module I opened another PowerShell session and got a list of processes as a baseline.

Then use the new cmdlet in a Job

Get-DataFile –AsJob

 

The job type is CimJob

A new process appears – wmiprvse. This the same process that appears with WMI jobs.  The path to the exe is C:\Windows\system32\wbem\wmiprvse.exe and the Description is: WMI Provider Host

This process provides isolation for WMI activities so that the whole of WMI isn’t pulled down in the event of a failure. 

The same process is started if Get-CimInstance Cim_Datafile is run.

CDXML–NetworkAdapterConfiguration–Search on Index

The Win32_NetworkAdapterConfiguration class has an Index and an InterfaceIndex property. Both are suitable search properties.

The take an unsigned integer as their value – leading to this addition to the CDXML file:

 

<Property PropertyName="Index">
<Type PSType = "System.UInt32"/>
<RegularQuery >
   <CmdletParameterMetadata PSName="Index" />
</RegularQuery>
</Property>

<Property PropertyName="InterfaceIndex">
<Type PSType = "System.UInt32"/>
<RegularQuery >
   <CmdletParameterMetadata PSName="InterfaceIndex" />
</RegularQuery>
</Property>

You can use the new parameters like this:

Get-NetworkAdapterConfiguration -Index 4

Get-NetworkAdapterConfiguration -InterfaceIndex 5

 

You should see by now how much easier it is working with cmdlets like this rather than having to remember the syntax for WQL filters and even the class names.

The full CDXML file looks like this

<?xml version='1.0' encoding='utf-8'?>
<PowerShellMetadata xmlns='http://schemas.microsoft.com/cmdlets-over-objects/2009/11'>
  <Class ClassName='ROOT\cimv2\Win32_NetworkAdapterConfiguration'>
    <Version>1.0</Version>
    <DefaultNoun>NetworkAdapterConfiguration</DefaultNoun>

    <InstanceCmdlets>
      <GetCmdletParameters DefaultCmdletParameterSet='DefaultSet'>
       
        <QueryableProperties>
           <Property PropertyName="DHCPEnabled">
            <Type PSType = "System.Boolean"/>
            <RegularQuery >
              <CmdletParameterMetadata PSName="DHCPEnabled" />
            </RegularQuery>
           </Property>
          
           <Property PropertyName="IPEnabled">
            <Type PSType = "System.Boolean"/>
            <RegularQuery >
              <CmdletParameterMetadata PSName="IPEnabled" />
            </RegularQuery>
           </Property>

           <Property PropertyName="Index">
            <Type PSType = "System.UInt32"/>
            <RegularQuery >
              <CmdletParameterMetadata PSName="Index" />
            </RegularQuery>
           </Property>

           <Property PropertyName="InterfaceIndex">
            <Type PSType = "System.UInt32"/>
            <RegularQuery >
              <CmdletParameterMetadata PSName="InterfaceIndex" />
            </RegularQuery>
           </Property>

       
        </QueryableProperties>
             
      </GetCmdletParameters>
    </InstanceCmdlets> 
  </Class>
</PowerShellMetadata>

 

The module manifest file hasn’t needed to be changed to add this additional functionality. One of the great things about CDXML is that once you have the basic cmdlet working it is so easy to add extra parameters.

 

The next step is to use some of the methods on the class

CDXML–NetworkAdapterConfiguration–IP Enabled

Last time we added a search parameter enabling this:

Get-NetworkAdapterConfiguration -DHCPEnabled $true

I also want to be able to search based on if the adapter if IP Enabled using:

Get-NetworkAdapterConfiguration -IPEnabled $true

This can be achieved by specifying another search parameter:

<Property PropertyName="IPEnabled">
<Type PSType = "System.Boolean"/>
<RegularQuery >
   <CmdletParameterMetadata PSName="IPEnabled" />
</RegularQuery>
</Property>

This the same as was done for DHCPEnabled except that the IPEnabled property is used.

The full XML now looks like this:

<?xml version='1.0' encoding='utf-8'?>
<PowerShellMetadata xmlns='http://schemas.microsoft.com/cmdlets-over-objects/2009/11'>
  <Class ClassName='ROOT\cimv2\Win32_NetworkAdapterConfiguration'>
    <Version>1.0</Version>
    <DefaultNoun>NetworkAdapterConfiguration</DefaultNoun>

    <InstanceCmdlets>
      <GetCmdletParameters DefaultCmdletParameterSet='DefaultSet'>
       
        <QueryableProperties>
           <Property PropertyName="DHCPEnabled">
            <Type PSType = "System.Boolean"/>
            <RegularQuery >
              <CmdletParameterMetadata PSName="DHCPEnabled" />
            </RegularQuery>
           </Property>
          
           <Property PropertyName="IPEnabled">
            <Type PSType = "System.Boolean"/>
            <RegularQuery >
              <CmdletParameterMetadata PSName="IPEnabled" />
            </RegularQuery>
           </Property>
       
        </QueryableProperties>
             
      </GetCmdletParameters>
    </InstanceCmdlets> 
  </Class>
</PowerShellMetadata>

CDXML–adding search parameters

Last time you saw how to create a cmdlet from the Win32_NetWorkAdapterConfiguration class:

<?xml version='1.0' encoding='utf-8'?>
<PowerShellMetadata xmlns='http://schemas.microsoft.com/cmdlets-over-objects/2009/11'>
  <Class ClassName='ROOT\cimv2\Win32_NetworkAdapterConfiguration'>
    <Version>1.0</Version>
    <DefaultNoun>NetworkAdapterConfiguration</DefaultNoun>

    <InstanceCmdlets>
      <GetCmdletParameters DefaultCmdletParameterSet='DefaultSet'>
             
      </GetCmdletParameters>
    </InstanceCmdlets> 
  </Class>
 
</PowerShellMetadata>

Now its time to add some parameters that can be used for searching.  This will be equivalent to performing these actions:

Get-CimInstance -ClassName Win32_NetworkAdapterConfiguration -Filter "DHCPEnabled='True'"

Get-CimInstance -ClassName Win32_NetworkAdapterConfiguration -Filter "IPEnabled='True'"

Get-CimInstance -ClassName Win32_NetworkAdapterConfiguration -Filter "Index=0"

Get-CimInstance -ClassName Win32_NetworkAdapterConfiguration -Filter "InterfaceIndex=3"

Lets start by looking at the DHCPEnabled property

£> $class = Get-CimClass -ClassName Win32_NetworkAdapterConfiguration
£> $class.CimClassProperties["DHCPEnabled"]

Name                            : DHCPEnabled
Value                             :
CimType                       : Boolean
Flags                              : Property, ReadOnly, NullValue
Qualifiers                      : {MappingStrings, read}
ReferenceClassName :

 

The parameter DHCPEnabled takes a Boolean value.  At the moment I don’t want anything clever like pipeline input – just the ability to use a parameter

This requirement translates to:

<?xml version='1.0' encoding='utf-8'?>
<PowerShellMetadata xmlns='http://schemas.microsoft.com/cmdlets-over-objects/2009/11'>
  <Class ClassName='ROOT\cimv2\Win32_NetworkAdapterConfiguration'>
    <Version>1.0</Version>
    <DefaultNoun>NetworkAdapterConfiguration</DefaultNoun>

    <InstanceCmdlets>
      <GetCmdletParameters DefaultCmdletParameterSet='DefaultSet'>
       
        <QueryableProperties>
           <Property PropertyName="DHCPEnabled">
            <Type PSType = "System.Boolean"/>
            <RegularQuery >
              <CmdletParameterMetadata PSName="DHCPEnabled" />
            </RegularQuery>
           </Property>
       
        </QueryableProperties>
             
      </GetCmdletParameters>
    </InstanceCmdlets> 
  </Class>
</PowerShellMetadata>

The changes are defined by the  <QueryableProperties> tags

        <QueryableProperties>

Define the WMI property you are searching on

           <Property PropertyName="DHCPEnabled">

Define the type of the data the parameter accepts

            <Type PSType = "System.Boolean"/>

Define the query type – in this case a straight forward search

            <RegularQuery >

Define the name you want the parameter to have  - doesn’t have to match the WMI property name
              <CmdletParameterMetadata PSName="DHCPEnabled" />
            </RegularQuery>
           </Property>
       
        </QueryableProperties>

 

You can use the changed cmdlet like this:

Get-NetworkAdapterConfiguration
Get-NetworkAdapterConfiguration -DHCPEnabled $true
Get-NetworkAdapterConfiguration -DHCPEnabled $false

The full syntax on the cmldet is:

Get-NetworkAdapterConfiguration [-DHCPEnabled <bool[]>]
[-CimSession <CimSession[]>] [-ThrottleLimit <int>]
[-AsJob]  [<CommonParameters>]

The cmdlets over objects technology automatically adds these parameters:

-CimSession

-ThrottleLimit

-AsJob

-CommonParameters

Next time we’ll add the other search properties

CDXML–network adapter configuration

I’ve amended the new-cdxml function created earlier in the series:

function new-cdxml {
[CmdletBinding()]
param (
[Parameter(Mandatory=$true)]
[string]$class,

[Parameter(Mandatory=$true)]
[string]$noun,

[string]$namespace = 'ROOT\cimv2',
[string]$path = "C:\Scripts\Modules\Hardware"
)

$code = @"
<?xml version='1.0' encoding='utf-8'?>
<PowerShellMetadata xmlns='http://schemas.microsoft.com/cmdlets-over-objects/2009/11'>
  <Class ClassName='$namespace\$class'>
    <Version>1.0</Version>
    <DefaultNoun>$noun</DefaultNoun>

    <InstanceCmdlets>
      <GetCmdletParameters DefaultCmdletParameterSet='DefaultSet'>
             
      </GetCmdletParameters>
    </InstanceCmdlets> 
  </Class>
 
</PowerShellMetadata>
"@

$file = Join-Path -Path $path -ChildPath "$class.cdxml"
Write-Verbose -Message  $file
Set-Content -Path $file -Value $code

}

 

The change is making the class and noun parameters mandatory. In PowerShell 3 & 4 you can simplify the syntax slightly:

param (
[Parameter(Mandatory)]
[string]$class,

[Parameter(Mandatory)]
[string]$noun,

[string]$namespace = 'ROOT\cimv2',
[string]$path = "C:\Scripts\Modules\Hardware"
)

 

I prefer to use the PowerShell 2.0 syntax and actually state that Mandatory=$true.  This is for 2 reasons. Firstly, its what I’m used to and it works – I haven’t got round to changing my default templates. Secondly, I prefer to use this syntax because its immediately apparent to me that the parameter is Mandatory.

This time I’ve used the Win32_NetworkAdapterConfiguration class because it enables me to introduce the use of search (filter) parameters in CDXML cmdlets; it has a number of very useful methods and it enables me to introduce the use of format files.

 

Using new-cdxml you can create the basic module

<?xml version='1.0' encoding='utf-8'?>
<PowerShellMetadata xmlns='http://schemas.microsoft.com/cmdlets-over-objects/2009/11'>
  <Class ClassName='ROOT\cimv2\Win32_NetworkAdapterConfiguration'>
    <Version>1.0</Version>
    <DefaultNoun>NetworkAdapterConfiguration</DefaultNoun>

    <InstanceCmdlets>
      <GetCmdletParameters DefaultCmdletParameterSet='DefaultSet'>
             
      </GetCmdletParameters>
    </InstanceCmdlets> 
  </Class>
 
</PowerShellMetadata>

 

To add this into the module manifest amend these two lines as shown:

# Modules to import as nested modules of the module specified in RootModule/ModuleToProcess
NestedModules = @('Win32_BIOS.cdxml',
                   'Win32_ComputerSystem.cdxml',
                   'Win32_DiskDrive.cdxml',
                   'Win32_NetworkAdapterConfiguration.cdxml'
                    )

# Functions to export from this module
FunctionsToExport = @('Get-Bios',
                      'Get-ComputerSystem',
                      'Get-PhysicalDisk',
                      'Get-NetworkAdapterConfiguration'
                      )

 

You now have a hardware module consisting of:

£> Get-Command -Module Hardware

CommandType     Name
-----------             ----
Function               Get-Bios
Function               Get-ComputerSystem
Function               Get-NetworkAdapterConfiguration
Function               Get-PhysicalDisk

 

The output from Get-NetworkAdapterConfiguration on my Windows 8.1 virtual machine looks like this:

ServiceName   DHCPEnabled   Index   Description
-----------        -----------         -----     -----------
netvsc             False                0          Microsoft Hyper-V Network Adapter
kdnic               True                 1          Microsoft Kernel Debug Network Adapter
tunnel             False                 3          Microsoft ISATAP Adapter
netvsc             False                4          Microsoft Hyper-V Network Adapter #2
tunnel             False                5          Microsoft ISATAP Adapter

 

Now this is the same display that Get-CimInstance produces and for my purposes it doesn’t work.  I need to create a format file to produce the display I need. I also want to be able to filter on various criteria including DHCPEnabled, IPEnabled, InterfaceIndex, Index  and Description. I also want to be able to search on any of these individually or in any logical combination

Transferring modules from Windows 8 or 8.1 to Windows 7

Windows 7 shipped with PowerShell 2.0 installed.  Windows 8 brought PowerShell 3.0 and Windows 8.1 brings PowerShell 4.0.

 

Windows 8 and 8.1 also have a lot of modules installed. This extra functionality widens PowerShell reach immensely – the networking modules alone are a significant step forward.

When you install PowerShell 3.0 or 4.0 on Windows 7 you don’t most of the new modules. This has puzzled many people and I’m often asked how those Windows 8/8.1 modules can be made available on Windows 7.

The short answer is that you can’t.

The long answer is that you can’t because, for the most part, those modules are based on CIM (WMI) classes that were introduced in Windows 8 or 8.1. A lot of the system management functionality you see in modern Windows is based on CIM classes that then use the CDXML approach to create PowerShell modules.

Installing the new CIM classes on Windows 7 is not possible – so you can’t get the modules on which they are based.

If you want the new functionality you have to upgrade to Windows 8.1