Advanced Windows PowerShell Scripting Video Training

Advanced Windows PowerShell Scripting Video Training
Advanced Windows PowerShell Scripting Video Training

Tuesday, March 22, 2016

Diving in deep with GetType()

When I deliver PowerShell classes, I emphasis the importance of sending the objects in the PowerShell Pipeline to Get-Member so you know what information is contained inside the object.  I also do it to get the typename of the object so I can do further research on MSDN.  Recently I’ve started using the .GetType() method if I only need the type information.  Get a look at the difference.

PS C:\> Get-Date | GM

   TypeName: System.DateTime

Name                 MemberType     Definition                                
----                 ----------     ----------                                
Add                  Method         datetime Add(timespan value)              
AddDays              Method         datetime AddDays(double value)            
AddHours             Method         datetime AddHours(double value)           
AddMilliseconds      Method         datetime AddMilliseconds(double value)    
AddMinutes           Method         datetime AddMinutes(double value)         
AddMonths            Method         datetime AddMonths(int months)            

… 60 members removed for this output …

TimeOfDay            Property       timespan TimeOfDay {get;}                 
Year                 Property       int Year {get;}                           
DateTime             ScriptProperty System.Object DateTime {get=if ((& { Set...

PS C:\> (Get-Date).GetType()

IsPublic IsSerial Name                                     BaseType            
-------- -------- ----                                     --------           
True     True     DateTime                                 System.ValueType   

A little bit easier to get SYSTEM.DATETIME from the second example.  One member of my PowerShell Toolmaking class asked me what does IsSerial mean?  Good question.  This one took a little bit of research.  I first had to figure out the object type that was giving me this information.

PS C:\> Get-Member -InputObject (Get-Date).GetType()

   TypeName: System.RuntimeType

Name                           MemberType Definition                          
----                           ---------- ----------                          
Equals                         Method     bool Equals(System.Object o), bool...
FindInterfaces                 Method     type[] FindInterfaces(System.Refle...
FindMembers                    Method     System.Reflection.MemberInfo[] Fin...
GetArrayRank                   Method     int GetArrayRank(), int _Type.GetA...
GetConstructor                 Method     System.Reflection.ConstructorInfo ...
GetConstructors                Method     System.Reflection.ConstructorInfo[...
GetCustomAttributes            Method     System.Object[] GetCustomAttribute...
GetCustomAttributesData        Method     System.Collections.Generic.IList[S...
GetDefaultMembers              Method     System.Reflection.MemberInfo[] Get...
GetElementType                 Method     type GetElementType(), type _Type....
GetEnumName                    Method     string GetEnumName(System.Object v...
GetEnumNames                   Method     string[] GetEnumNames()             
GetEnumUnderlyingType          Method     type GetEnumUnderlyingType()        
GetEnumValues                  Method     array GetEnumValues()               
GetEvent                       Method     System.Reflection.EventInfo GetEve...
GetEvents                      Method     System.Reflection.EventInfo[] GetE...
GetField                       Method     System.Reflection.FieldInfo GetFie...
GetFields                      Method     System.Reflection.FieldInfo[] GetF...
GetGenericArguments            Method     type[] GetGenericArguments()        
GetGenericParameterConstraints Method     type[] GetGenericParameterConstrai...
GetGenericTypeDefinition       Method     type GetGenericTypeDefinition()     
GetHashCode                    Method     int GetHashCode(), int _MemberInfo...
GetIDsOfNames                  Method     void _MemberInfo.GetIDsOfNames([re...
GetInterface                   Method     type GetInterface(string name), ty...
GetInterfaceMap                Method     System.Reflection.InterfaceMapping...
GetInterfaces                  Method     type[] GetInterfaces(), type[] _Ty...
GetMember                      Method     System.Reflection.MemberInfo[] Get...
GetMembers                     Method     System.Reflection.MemberInfo[] Get...
GetMethod                      Method     System.Reflection.MethodInfo GetMe...
GetMethods                     Method     System.Reflection.MethodInfo[] Get...
GetNestedType                  Method     type GetNestedType(string name), t...
GetNestedTypes                 Method     type[] GetNestedTypes(), type[] Ge...
GetProperties                  Method     System.Reflection.PropertyInfo[] G...
GetProperty                    Method     System.Reflection.PropertyInfo Get...
GetType                        Method     type GetType(), type _MemberInfo.G...
GetTypeInfo                    Method     void _MemberInfo.GetTypeInfo(uint3...
GetTypeInfoCount               Method     void _MemberInfo.GetTypeInfoCount(...
Invoke                         Method     void _MemberInfo.Invoke(uint32 dis...
InvokeMember                   Method     System.Object InvokeMember(string ...
IsAssignableFrom               Method     bool IsAssignableFrom(type c), boo...
IsDefined                      Method     bool IsDefined(type attributeType,...
IsEnumDefined                  Method     bool IsEnumDefined(System.Object v...
IsEquivalentTo                 Method     bool IsEquivalentTo(type other)     
IsInstanceOfType               Method     bool IsInstanceOfType(System.Objec...
IsSubclassOf                   Method     bool IsSubclassOf(type c), bool _T...
MakeArrayType                  Method     type MakeArrayType(), type MakeArr...
MakeByRefType                  Method     type MakeByRefType()                
MakeGenericType                Method     type MakeGenericType(Params type[]...
MakePointerType                Method     type MakePointerType()              
ToString                       Method     string ToString(), string _MemberI...
Assembly                       Property   System.Reflection.Assembly Assembl...
AssemblyQualifiedName          Property   string AssemblyQualifiedName {get;} 
Attributes                     Property   System.Reflection.TypeAttributes A...
BaseType                       Property   type BaseType {get;}                
ContainsGenericParameters      Property   bool ContainsGenericParameters {get;}
CustomAttributes               Property   System.Collections.Generic.IEnumer...
DeclaringMethod                Property   System.Reflection.MethodBase Decla...
DeclaringType                  Property   type DeclaringType {get;}           
FullName                       Property   string FullName {get;}              
GenericParameterAttributes     Property   System.Reflection.GenericParameter...
GenericParameterPosition       Property   int GenericParameterPosition {get;} 
GenericTypeArguments           Property   type[] GenericTypeArguments {get;}  
GUID                           Property   guid GUID {get;}                    
HasElementType                 Property   bool HasElementType {get;}          
IsAbstract                     Property   bool IsAbstract {get;}              
IsAnsiClass                    Property   bool IsAnsiClass {get;}             
IsArray                        Property   bool IsArray {get;}                 
IsAutoClass                    Property   bool IsAutoClass {get;}             
IsAutoLayout                   Property   bool IsAutoLayout {get;}            
IsByRef                        Property   bool IsByRef {get;}                 
IsClass                        Property   bool IsClass {get;}                 
IsCOMObject                    Property   bool IsCOMObject {get;}             
IsConstructedGenericType       Property   bool IsConstructedGenericType {get;}
IsContextful                   Property   bool IsContextful {get;}            
IsEnum                         Property   bool IsEnum {get;}                   
IsExplicitLayout               Property   bool IsExplicitLayout {get;}        
IsGenericParameter             Property   bool IsGenericParameter {get;}      
IsGenericType                  Property   bool IsGenericType {get;}           
IsGenericTypeDefinition        Property   bool IsGenericTypeDefinition {get;} 
IsImport                       Property   bool IsImport {get;}                
IsInterface                    Property   bool IsInterface {get;}             
IsLayoutSequential             Property   bool IsLayoutSequential {get;}      
IsMarshalByRef                 Property   bool IsMarshalByRef {get;}          
IsNested                       Property   bool IsNested {get;}                
IsNestedAssembly               Property   bool IsNestedAssembly {get;}        
IsNestedFamANDAssem            Property   bool IsNestedFamANDAssem {get;}     
IsNestedFamily                 Property   bool IsNestedFamily {get;}          
IsNestedFamORAssem             Property   bool IsNestedFamORAssem {get;}      
IsNestedPrivate                Property   bool IsNestedPrivate {get;}         
IsNestedPublic                 Property   bool IsNestedPublic {get;}          
IsNotPublic                    Property   bool IsNotPublic {get;}             
IsPointer                      Property   bool IsPointer {get;}               
IsPrimitive                    Property   bool IsPrimitive {get;}             
IsPublic                       Property   bool IsPublic {get;}                
IsSealed                       Property   bool IsSealed {get;}                
IsSecurityCritical             Property   bool IsSecurityCritical {get;}      
IsSecuritySafeCritical         Property   bool IsSecuritySafeCritical {get;}  
IsSecurityTransparent          Property   bool IsSecurityTransparent {get;}   
IsSerializable                 Property   bool IsSerializable {get;}          
IsSpecialName                  Property   bool IsSpecialName {get;}           
IsUnicodeClass                 Property   bool IsUnicodeClass {get;}          
IsValueType                    Property   bool IsValueType {get;}             
IsVisible                      Property   bool IsVisible {get;}               
MemberType                     Property   System.Reflection.MemberTypes Memb...
MetadataToken                  Property   int MetadataToken {get;}            
Module                         Property   System.Reflection.Module Module {g...
Name                           Property   string Name {get;}                  
Namespace                      Property   string Namespace {get;}             
ReflectedType                  Property   type ReflectedType {get;}           
StructLayoutAttribute          Property   System.Runtime.InteropServices.Str...
TypeHandle                     Property   System.RuntimeTypeHandle TypeHandl...
TypeInitializer                Property   System.Reflection.ConstructorInfo ...
UnderlyingSystemType           Property   type UnderlyingSystemType {get;}    

Wow! A lot of information here.  The first that I was able to get was the typename.  It took some browsing around, but I found the object information on MSDN.
The problem that I have now is that IsSerial is not listed in the member information.  I can see IsSerializable is there, but I need to confirm that the column named IsSerial represents IsSerializable.  Here is a little code that will comb all of PowerShell’s formatting files and tell you where to find the correct XML file to investigate.

$Files = Get-ChildItem -Recurse -Path "C:" -Name "*.format.ps1xml"

ForEach ($F in $Files)
  ForEach ($Data in (Get-Content -Path "C:\$F"))
    If ($Data -like "*System.RuntimeType*")
    {Write-Host "Found: $F" -ForegroundColor Green}

When I run this code, I find 2 potential candidates:
Found: Windows\System32\WindowsPowerShell\v1.0\PowerShellCore.format.ps1xml
Found: Windows\System32\WindowsPowerShell\v1.0\PowerShellCore.format.ps1xml
Found: Windows\SysWOW64\WindowsPowerShell\v1.0\PowerShellCore.format.ps1xml
Found: Windows\SysWOW64\WindowsPowerShell\v1.0\PowerShellCore.format.ps1xml
Found: Windows\WinSxS\
Found: Windows\WinSxS\
Found: Windows\WinSxS\
Found: Windows\WinSxS\

After evaluating the formatting file, I was able to confirm the IsSerial represents IsSerializable.

So, what does this property mean?  In basic terms, it allows the contents of this object to be saved to disk.  Yes, a lot of research needed to be done. To make sure that you understand what you are looking at, you need to do your research.

Welcome to Computer Science.

Wednesday, March 9, 2016

Just for fun - Storing BLOB files as XML

So, one of the reasons why I like to teach PowerShell is that every once and a while, someone comes up with an unusual idea. So here it goes.  Can you save a BLOB file in an XML file?  This is strictly for the sake of theory.  In the process, we discovered some different behavior of Get-Content.
Off the top of my head, the only way that I knew how to create a BLOB file is with an Offline Domain Join.  Here is the Wikipedia definition of a BLOB:

A Binary Large Object (BLOB) is a collection of binary data stored as a single entity in a database management system. Blobs are typically images, audio or other multimedia objects, though sometimes binary executable code is stored as a blob.

An Offline Domain Join allows you to create an object in Active Directory for a new client without the client being available.  It also allows to client to be configured to join the domain once it is able to contact a Domain Controller.  To get this to work, you need to create a BLOB file with the DJoin command and send that BLOB file to the client. 

So, here we go….

This will execute the provisioning portion of an ODJ.  Since this is a PowerShell class, I used Invoke-Expression.

# Offline Domain Join

Invoke-Expression -Command "djoin /provision /domain /machine LON-SVR1 /SaveFile C:\PS\DJoin.txt"

Here is what the BLOB file looks like.  Not much to look at.
# View the BLOB
Get-Content -Path C:\ps\DJoin.txt

# Save as an CliXML
Get-Content -Path C:\ps\DJoin.txt | Export-Clixml -Path c:\ps\DJoin.xml

# View the XML File
Notepad C:\ps\DJoin.xml
Unfortunately, I cannot display the XML file in this blog.  Go ahead and take a look at it. Keep scrolling down, something is not right.  This is what threw my off.  Take a close look.  There is a lot more information here than the String object sent to Export-CliXML.  As a matter of fact, I’m seeing the size of my hard drive!!!! The reason is that Get-Content added a few note properties.

PS C:\> Get-Content -Path C:\ps\DJoin.xml | Get-Member -MemberType NoteProperty

   TypeName: System.String

Name         MemberType   Definition                                                                        
----         ----------   ----------                                                                         
PSChildName  NoteProperty System.String PSChildName=DJoin.xml                                               
PSDrive      NoteProperty System.Management.Automation.PSDriveInfo PSDrive=C                                
PSParentPath NoteProperty System.String PSParentPath=C:\ps                                                  
PSPath       NoteProperty System.String PSPath=C:\ps\DJoin.xml                                              
PSProvider   NoteProperty System.Management.Automation.ProviderInfo PSProvider=Microsoft.PowerShell.Core\F...
ReadCount    NoteProperty System.Int64 ReadCount=1                                                          

These are not part of a normal string object.  These note properties are responcible for some of the excess information in the XML.  At this point, I was thinking that this is going to fail at the client end.  In any case, the provisioning worked:
PS C:\ps> Get-ADComputer -Identity LON-SVR1

DistinguishedName : CN=LON-SVR1,CN=Computers,DC=Adatum,DC=com
DNSHostName       :
Enabled           : True
Name              : LON-SVR1
ObjectClass       : computer
ObjectGUID        : b2c4be2e-bcbb-48cc-be8c-18313600d8ac
SamAccountName    : LON-SVR1$
SID               : S-1-5-21-1203837507-141498335-1392284353-4103
UserPrincipalName : 

Next we manually copied the XML file to the destination client and executed these commands.
# Create a new directory.
New-Item -Path c: -Name PS -ItemType Directory

# Import the XML File
Import-Clixml -Path C:\ps\DJoin.xml | Out-file -FilePath c:\ps\djoin.txt

Invoke-Expression -Command "djoin /requestodj /loadfile c:\ps\djoin.txt  /WindowsPath c:\Windows /localos"

We received the normal restart required command and after the restart, the client was on the domain. Surprise!!!!!
OK, again, this was just for the sake of theory.  No practical usage was implied.  We were just having some fun.