Advanced Windows PowerShell Scripting Video Training

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

Thursday, June 30, 2011

SCVMM Error (2912) when creating a VM from the Self-Service Portal workaround

While using the Self Service Portal on SCVMM, I received this error when creating a virtual machine.

 

Error (2941)
VMM is unable to complete the request. The connection to the agent on machine [SCVMMServer] has been lost.
(Unknown error (0x80072efe))

Recommended Action
Ensure that the WS-Management service and the agent are installed and running and that a firewall is not blocking HTTP traffic.

 

In the job details, the error occurred at step 1.5 Install VM Components.  This issue was reported to Microsoft on October 12, 2008.  The suggested fix on June 26, 2011 does work, but with an issue.  If you were using quotas to help manage the resources your users were consuming, the record of this quota usage will be lost.  The users quota will have those points returned to it as if they are not being used.

 

To prevent the loss of data associated with the host, here is an easy alternative.

 

  • Go to the Hyper-V manager on the host that the deployed VM resides on.
  • Make sure the correct VHD files are attached and that correct virtual network is attached.
  • Start the VM and finish any installation activities from the deployment.
  • Install the integration services if necessary.
  • Properly shut down the VM.
  • Start the VM back up.
  • In the VMM manager console, right click the VM and select Repair.
  • The only option you should get is Retry.  Should Ignore be an option, us it.
  • Let the process finish.  If it errors again, attempt the Repair.  You want it to present to you the option of Ignore. Once you can ignore the errors, your VM will be functional in the VMM console.

 

This procedure is a bit awkward, but it preserves not only the quota points, but all settings and database information associated with the host.

Wednesday, June 29, 2011

How many hosts and VMs can VMM R2 support?

System Center Virtual Machine Manager can support up to 400 hosts running up to 8,000 virtual machines.  If your needs go beyond this, remember these tips:
  • Each instance of VMM Server must be installed on a separate computer.
  • Each instance must have its own database.
  • Each host or library can only be managed by one VMM server at any one time.

Monday, June 27, 2011

Private IP Address

The Internet Assigned Numbers Authority (IANA) have reserved the following IPv4 ranges for internal, private use.

 

IP Address Range Subnet Number of addresses
10.0.0.0-10.255.255.255 255.255.255.0 16,777,216
172.16.0.0 – 172.31.255.255 255.240.0.0 1,048,476
192.168.0.0 – 192.168.255.255 255.255.0.0 65,536

 

The IPv6 equivalent has an address block of fc00::/7

Friday, June 24, 2011

Where is the VMM Server setup log located?

The setup log for VMM is located at c:\ProgramData\VMMLogs\ServerSetup.log

Wow, much shorter than my normal posts, but this question does not have a long answer.

Thursday, June 23, 2011

Manually Deploy SCVVM Agent

The System Center Virtual Machine Manager (SCVMM) agent allows a SCVMM server to manage the virtual machines on that host. When you use the SCVMM console to add a host, the SCVMM agent software is installed on that host. If the host is in a perimeter network or not on the domain, you need to add the agent software manually before joining it to a VMM server.

Before you install the SCVMM agent, your host must meet the following requirements. (List below provided by Microsoft)

· Microsoft Virtual Server 2005 R2 or above.

· Microsoft Virtual Server 2005 R2 x64 SP1 or above.

If you are using Windows Server 2008, you are good to go. These instructions are valid for installing SC VMM agent on a host in a trusted domain.

Double click Setup.exe from the installation media of SCVMM

Click Local Agent.

clip_image002

Click Next.

Check I accept the terms of this agreement and click Next.

Choose the location of where you want the agent to install to and click Next.

On the Configuration Settings page, you must configure the agent to use the same ports as the SC VMM server. Click Next.

If this host is on a perimeter network, you need to configure the authentication between the host and the VMM server. You can do this via a security file or a certificate. Click Next.

Click Install.

Wednesday, June 22, 2011

Super netting

Even though we appear to be in the twilight years of IPv4, you may still be faced with the question of super netting.

In the IPv4 world, we use a subnet mask to separate the network and host portion of an IP address.  With the IP address divided into 4 groups representing 8 bits, the normal subnets look like this:

255.0.0.0

255.255.0.0

255.255.255.0


The 255 is the decimal representation of 8 bits, all set to ‘1’.  The 0’s are the decimal representation of 8 bits, all set to ‘0’.  This makes subnetting easy.  Let’s say you need a subnet that can handle 4000 hosts?  Standard subnets will not work.  Here is how you figure out the subnet ID

Convert the 4000 to binary.  User the programmer mode on the Windows calculator

Just type in 4000 in DEC mode, and then switch to BIN mode.

image

The binary for this is 11111010000

If we add some leading zeros to make this an even 16 bit number, we get

0000111110100000

Now, place them into octets.

00001111.10100000

We can see by the leading one, that we need to borrow the lower 4 bits of the third octet for use as the host ID.  The leading 4 will be used as part of the network ID. In Window calculator, let’s figure out what just the first 4 leading bits will be.  To do this, set the calculator in BIN mode and type 11110000.  Now click DEC mode. You get the number 240.  Your subnet mask is:

255.255.240.0 or 11111111.11111111.11110000.00000000

There are also a limited number of subnets possible with subnetting.  We will continue to use the above subnet of 255.255.240.0 as our example.  Since we can only use the leading 4 bits for the network ID, we have to calculate the possible subnets.

00000000 ---- 0
00010000 ---- 16
00100000 ---- 32
00110000 ---- 48
01000000 ---- 64
01010000 ---- 80
01100000 ---- 96
01110000 ---- 112
10000000 ---- 128
10010000 ---- 144
10100000 ---- 160
10110000 ---- 176
11000000 ---- 192
11010000 ---- 208
11100000 ---- 224
11110000 ---- 240


Of these 16 subnets, the first and last one are reserved.  We only have 14 available subnets.

The IP address is derived from a combination of the bits from the host portion, and the network portion.  Let’s say that we need to use the last two bits of the third octet, and the first 6 of the fourth for our host ID.

00000011.11111100

We know that the first four bits are reserved for the network ID.  Lets place this in the 192 subnet.  Out subnet ID will look like this.

11111111.11111111.11000000.00000000

Let’s combine our host and network IDs

11111111.11111111.11000011.11111100

Running the 3rd octet through the Windows Calculator, we get 195.  If our network ID is 10.10.xxx.yyy, we can now determine that out IP address is 10.10.195.252

This is a very complicated method.  The link below will take you to a chart on the internet to try and help you determine the number of subnets and hosts a particular network can support.
http://www.pantz.org/software/tcpip/subnetchart.html

Tuesday, June 21, 2011

Setting DNS and Default Gateway Settings for IPv6 with DHCPv6

This is a posting in response to my posting last October about how to set up DHCP on Windows Server 2008 to deliver IPv6 addresses. The question was how to publish the DNS and Default Gateway addresses to your IPv6 clients.  I’m sorry to say that the Microsoft implementation of DHCPv6 does not have these options.  So, here is an alternative…Create a login script.

After reading through the manual method posted at TechNet, I found two examples.  One to set the Default Gateway and one to set the DNS addresses.  Below is the relevant sections of that TechNet article with the examples in red.
Adding Default Gateways
To configure a default gateway, you can use the netsh interface ipv6 add route command and add a default route (::/0) with the following syntax:
netsh interface ipv6 add route [prefix=]::/0 [interface=]Interface_Name_or_Index [[nexthop=]IPv6_Address] [[siteprefixlength=]Length] [[metric=]Metric_Value] [[publish=]no|yes|immortal] [[validlifetime=]Time|infinite] [[preferredlifetime=]Time|infinite] [[store=]active|persistent]
  • prefix The IPv6 address prefix and prefix length for the default route. For other routes, you can substitute ::/0 withAddress_Prefix/Prefix_Length.
  • interface The connection or adapter's name or interface index.
  • nexthop If the prefix is for destinations that are not on the local link, the next-hop IPv6 address of a neighboring router.
  • siteprefixlength If the prefix is for destinations on the local link, you can optionally specify the prefix length for the address prefix assigned to the site to which this IPv6 node belongs.
  • metric A value that specifies the preference for using the route. Lower values are more preferred.
  • publish As an IPv6 router, this option specifies whether the subnet prefix corresponding to the route will be included in router advertisements and whether the lifetimes for the prefixes are infinite (the immortal option).
  • validlifetime The lifetime over which the route is valid. Time values can be expressed in days, hours, minutes, and seconds, for example 1d2h3m4s. The default value is infinite.
  • preferredlifetime The lifetime over which the route is preferred. Time values can be expressed in days, hours, minutes, and seconds. The default value is infinite.
  • store How to store the route, either active (route is removed upon system restart) or persistent (route remains after restart) (default).
For example, to add a default route that uses the interface named "Local Area Connection" with a next-hop address of fe80::2aa:ff:fe9a:21b8, you would use the following command:
netsh interface ipv6 add route ::/0 "Local Area Connection" fe80::2aa:ff:fe9a:21b8
Adding DNS Servers
To configure the IPv6 addresses of DNS servers, you can use the netsh interface ipv6 add dnsserver command with the following syntax:
netsh interface ipv6 add dnsserver [interface=]Interface_Name_or_Index [[address=]IPv6_Address] [[index=]Preference_Value]
  • interface The connection or adapter's name or interface index.
  • address The IPv6 address of the DNS server.
  • index The preference for the DNS server address.
    By default, the DNS server is added to the end of the list of DNS servers. If an index is specified, the DNS server is placed in that position in the list and the other DNS servers are moved down the list.
For example, to add a DNS server with the IPv6 address 2001:db8::99:4acd::8 that uses the interface named "Local Area Connection," you would use the following command:
netsh interface ipv6 add dnsserver "Local Area Connection" 2001:db8::99:4acd::8

Monday, June 20, 2011

Can you have more than 4 partitions on an MBR disk if they do not have assigned driver letters?

This question came up during a 6292 class.  To test this out I created a Windows 7 Virtual machine and added a 5 GB hard drive to it.

I then brought the hard drive online as an MBR disk and began creating simple volumes of 8 MB in size.  Instead of drive letter, I selected Do not assign a drive letter or drive path.

image

Once I created the fourth partition, the limit of an MBR disk, Disk Manager created an extended partition.

image

I could continue to add partitions within the extended partition.

image

I then converted Disk 1 to a GPT disk.

image

That allowed me to continue adding partitions.

image

I also tried deleting all the volumes and then using the Diskpart tool to create the partitions:

image

Just for the fun of it, I converted the drive to a GPT disk and was able to successfully create 127 partitions.

image

Friday, June 17, 2011

WUAUCLT Switches

In Lab 12 of 6294: Planning and Managing Windows 7 Desktop Deployments and Environments, we had a question about the parameters for Wuauclt.  In our books, the short versions of the parameters were used.

Despite the documentation at Microsoft on the wuauclt command, the help file does not display.  Here are the parameters that I have been able to find information on.
/a  or /ResetAuthorization
Initiates an asynchronous background search for applicable updates. If Automatic Updates is disabled, this option has no effect.

/r  or /ReportNow
Sends all queued reporting events to the server asynchronously.

/detectnow
Allows a client to start the detection process immediately.

Below is the list of switches that I have not been able to get definitive answers on.
/RunHandlerComServer
/RunStoreAsComServer
/ShowSettingsDialog
/ResetEulas
/ShowWU
/ShowWindowsUpdate
/SelfUpdateManaged
/SelfUpdateUnmanaged
/UpdateNow
/ShowWUAutoScan
/ShowFeaturedUpdates
/ShowOptions
/ShowFeaturedOptInDialog
/DemoUI

Note that when combining parameters, you can use them only in the order specified as follows:
wuauclt.exe /resetauthorization /detectnow

Thursday, June 16, 2011

Excel Boarder Properties with PowerShell

The function below will display the values of various properties of borders in Excel.  This script is designed to help programmers find the appropriate values that they need.
<#
.SYNOPSIS
Displays the attributes and results for
several Excel boarder Properties.
.DESCRIPTION
This function will launch an Excel spreadsheet.
It will then display the properties for style,
color, and weight for borders.
#>

Function Display-ExcelBoarders
{
$a = New-Object -comobject Excel.Application

$a.Visible = $True

$b = $a.Workbooks.Add()
$c = $b.Worksheets.Item(1)


# Display Borders

# Column Header
$C.Cells.Item(1,1) = ".Borders.LineStyle = "

# AutoSize the Column
$C.Cells.Item(1,1).EntireColumn.AutoFit()

# Valid range for LineStyle is 0 through 13. 
For ($x=0;$x -lt 14; $x++)
{
$C.Cells.Item($x+2,1) =  $x
$C.Cells.Item($x+2,1).Borders.LineStyle = $x    
}

# Border Color
# Column Header
$C.Cells.Item(1,3) = ".Borders.ColorIndex = "

# AutoSize the Column
$C.Cells.Item(1,3).EntireColumn.AutoFit()

# Valid range for ColorIndex is 0 through 55. 
For ($x=0;$x -lt 56; $x++)
{
$C.Cells.Item($x+2,3) =  $x
$C.Cells.Item($x+2,3).Borders.ColorIndex = $x    
$C.Cells.Item($x+2,3).borders.weight = 4
}

# Border Weight
# Column Header
$C.Cells.Item(1,5) = ".Borders.Weight = "

# AutoSize the Column
$C.Cells.Item(1,5).EntireColumn.AutoFit()

# Valid range for Weight is 0 through 4. 
For ($x=0;$x -lt 5; $x++)
{
$C.Cells.Item($x+2,5) =  $x    
$C.Cells.Item($x+2,5).borders.weight = $x
}

# Author Information
$C.Cells.Item(1,7) = "Jason Yoder"
$C.Cells.Item(2,7) = "www.MCTExpert.com"



}

Wednesday, June 15, 2011

Hyper-V R2 SP1 Dynamic Memory

Until now, you were not able to over allocate RAM to virtual machines running Hyper-V.  You could allocate enough static RAM to a set of VMs that would exceed the total amount of RAM on the server, but you would not be able to start all your virtual machines.

Part of server consolidation is the ability to take servers that are underutilized and move their operations to a single server.  This has worked well however, even when a virtual machine was not taxed to its maximum memory load, it still consumed the same amount of memory and therefor was a hindrance to further consolidation.

Dynamic memory allows you to safely increase the VM density on a server.  This feature requires Windows Server 2008 R2 SP1 and is available on the following guest partitions:
  • Windows Server 2003 Enterprise and Datacenter with SP2 (32 and 64-bit versions)
  • Windows Server 2003 R2 Enterprise and Datacenter with SP2 (32 and 64-bit versions)
  • Windows Server 2008 Enterprise and Datacenter (32 and 64-bit versions)
  • Windows Server 2008 R2 Enterprise and Datacenter (32 and 64-bit versions)
  • Windows Vista Ultimate and Enterprise with SP1 (32 and 64-bit versions)
  • Windows 7 Ultimate and Enterprise  (32 and 64-bit versions)

After installing Windows Server 2008 R2 SP1, I ran a test of the dynamic memory option.  Dynamic memory is not enabled by default.  The screen shot below shows the memory page of a VM on the upgraded server.
image
Two new areas have been added, Dynamic and the Memory weight.

In the Dynamic Memory area, you must first decide on the minimal amount of RAM that is required to start the VM.  The Maximum RAM setting is the upper limit of RAM that you will allocate to this VM.  You cannot use this option to assign more RAM than is physically on the server.  64GB is still the upper limit for a virtual machine. 

The Memory Buffer allows you to specify additional RAM above the current workload requirements.  If it is available, your VM will have additional RAM to work with

The Memory Weight option allows you to establish a pecking order among your VMs to decide who gets additional RAM when the free pool of RAM is depleted.

The Memory Weight and Memory Buffer are the only two memory settings that can be adjusted while a VM is running.  Changing between static and dynamic or adjusting dynamic memory requires the VM to be shut down.

The Hyper-V Manager also has some new columns added to it:
image
The Assigned Memory always starts at the Startup RAM value.  The Memory Demand lets you know how much RAM is actually being used. The VM that is not reporting Memory Demand is configured for static memory.

You also need to install SP1 on your VMs to take fully advantage of Dynamic memory.  Re-installing the integration services will also provide this functionality, but Microsoft recommends that you upgrade all VMs to SP1.

More information can be found by following this link to Microsoft.

Tuesday, June 14, 2011

Test to see if a file exists using PowerShell

Normally I would use just the Test-Path cmdlet for this.  The requirement of a project that I’m on needed a “user friendly” output option as well.  Below is an example of that user friendly output.
image
Here is the code:

<#
.SYNOPSIS
Test to see if a file exists.
.DESCRIPTION
Returns TRUE if the file submitted is exists.
Returns FALSE if it does not.
.PARAMETER ExcelFile
The name of the file being tested
.EXAMPLE
get-excelFile Det1.xls -DisplayInfo
File found
True

Verifies that a file names "Det1.xls" exists and also
displays the user friendly information of "File Found"
to the display.  The value of TRUE was returned to the 
pipeline.

.EXAMPLE
get-excelFile "demo.xls"
File not found

Verified that the file named "demo.xls" did not exist
in the location specified.  The value FALSE was
returned to the pipeline.
#>

Function Get-File
{
Param (
[Parameter(Position=0,Mandatory=$True)]$File,
[Switch]$DisplayInfo = $False
)

If (Test-Path $File)
{
# Displays user friendly info on the display.
    If ($DisplayInfo) 
{
Write-Host "File found" -ForegroundColor Green
}
Write-Output $True}
Else {
# Displays user friendly info on the display.
    If ($DisplayInfo) 
{
Write-Host "File not found" -ForegroundColor Red
}
Write-Output $False
}

Monday, June 13, 2011

If a VM was in a VLAN, can an outside client make a RDP?

The idea behind a VLAN is isolation.  On the same Hyper-V Server, the two clients in question would have to connected to the same virtual network to communicate.  This defeats the purpose of this question. 

I set up two different VMs on 2 different Hyper-V Servers.  Both were placed on external Virtual Networks and were able to PING each other.  On one of the virtual networks, I enabled VLAN with an ID of 2.  I also enabled it in the settings of the VM.  Once this change took effect, the two VMs lost communication with each other.

In conclusion, the VLAN also isolates, as it should, communication between clients for both the virtual and physical worlds.  Therefore, no RDP traffic can pass between them.

Friday, June 10, 2011

If you transfer a user’s settings using USMT into a client that they already have a profile in, what will happen?

In the config.xml file, you can create merge rules for your data.  Below is an example of the xml code for a merge rule.  You can read the complete article from Microsoft here.
<merge script>="MigXmlHelper.DestinationPriority()"> 
<objectSet> 
<pattern type="file">c:\data\* [*]<pattern> 
</objectSet> 
</merge>

During ScanState, all the files will be added to the store.

During LoadState, only C:\Data\SampleA.txt will be restored.
 
 
<merge script>="MigXmlHelper.SourcePriority()"> 
<objectSet> 
<pattern type="file">c:\data\* [*]<pattern> 
</objectSet> 
</merge> 

During ScanState, all the files will be added to the store.

During LoadState, all the files will be restored (overwriting the existing files on the destination computer).
 
 
<merge script>="MigXmlHelper.SourcePriority()"> 
<objectSet> 
<pattern type="file">c:\data\ [*]<pattern> 
</objectSet> 
</merge> 

During ScanState, all the files will be added to the store.

During LoadState, the following will occur:

  • C:\Data\SampleA.txt will be restored.
  • C:\Data\SampleB.txt will be restored (overwriting the existing file on the destination computer).
  • C:\Data\Folder\SampleB.txt will not be restored.

Thursday, June 9, 2011

How do I know if DFS Replication is completed using PowerShell?

You can check the state of DFS-Replication by using the DFSRDiag command.  If replication was in progress, you would see these results
dfsrdiag RepliationState
Updates served:
[1] Update name: user32.amx
[2] Update name: gdi32.amx
[3] Update name: report.docx
[4] Update name: Train.pptx
Total number of Outbound updates being served: 4

Summary
Active inbound connections: 0
Updates Received: 0
Active outbound connections: 1
Updates sent out: 4
Operation Succeeded

This must be ran on a server with DFS installed on it.  Your exact results will depend on what is being transferred.

To do this in PowerShell, I created a function that sends a value of True into the pipeline if DFS replication is active and False if it is not.  Here is the code:

<#
.SYNOPSIS
Test to determine if DFS replication is in progress

.DESCRIPTION
Returns [Boolean]TRUE if replication is in progress.
Returns [Boolean]FALSE if replication is not in progress.

.EXAMPLE
Test-DFSRProgress

True

The example returned True.  That means DFS
replication is in progress.

.NOTES
This function can only be executed on a server
with DFS installed.  It will only test for
DFS replication to and from this executing
server.

.LINK
Invoke-Command
#>

Function Test-DFSRProgress
{
# Execute the MS Dos command "DFSRDiag ReplicatoinState"
    # and store the output in the variable $DFSRInfo.
    $DFSRInfo = Invoke-Command -ScriptBlock {DFSRDiag ReplicationState}

# Test to see if the output has the below strings in it.
    # if it does not, then replication is in progress.
    If ($DFSRInfo -like "*Active inbound connections: 0*" -and $DFSRInfo -like "*Active outbound connections: 0*")
{Write-Output $False}
Else {Write-Output $True}
}

Wednesday, June 8, 2011

How to determine the number of physical processors on a client in PowerShell.

There seems to be a bit of a debate on the internet about this one.  I executed the following PowerShell command on 2 different computers:

Get-WMIObject Win32_ComputerSystem | FL *

 

I executed it on a laptop with 1 physical processor with 4 logical processors and received the following results:

 

image

 

I then executed it again on a desktop with 1 physical processor and 8 logical processors:

 

image

 

From my testing, the NumberOfProcessors property seems to provide the correct number of physical processors.

 

I got curios and ran that PowerShell code on a virtual machine with 1 assigned processor:

 

image

 

I also ran it on a virtual machine with 4 processors assigned to it:

 

image

 

OK, so how do you know if you are looking at a virtual machine or a physical machine?  A couple of properties higher in the list you will see Model.  If this was a virtual machine, it would say Virtual Machine.

 

image

Tuesday, June 7, 2011

Use PowerShell to determine which groups a set of users have in common

From my PowerShell class in May, here is one of the problems a student wanted PowerShell to help with.  He needed a script that will let him feed in a list of user names and output which groups that all the users were members of.  Below is the code to do that.  Remember that you can Dot Source this into your shell or turn it into a module.

<#
.SYNOPSIS
Takes a list of users and displays the groups that
they have in common.

.DESCRIPTION
Utilizes Active Directory to take a list of users
and enumerates all the groups that the users have in
common.

.PARAMETER UserList
Comma delimited list of user names that are to
be processed.

.PARAMETER ListAll
Displays not only the groups that all users
are members of, but also the groups that at
least one user is not a member of.

.EXAMPLE
compare-group g:\userlist.txt | FT -AutoSize

Name         UserPresent
----         -----------
Domain Users        True
Marketing           True

Description
-----------
Imports a txt file containing the SAMAccountName of
the users that you want to examine.  It is then piped to
Format-Table and auto sized it to make the data more readable.



.EXAMPLE
F:\mod09\democode> compare-Group g:\UserList.txt -ListAll | FT -AutoSize

Name                                    UserPresent
----                                    -----------
Administrators                                False
Users                                         False
Guests                                        False
Print Operators                               False
Backup Operators                              False
Replicator                                    False
Remote Desktop Users                          False
Network Configuration Operators               False
Performance Monitor Users                     False
Performance Log Users                         False
Distributed COM Users                         False
IIS_IUSRS                                     False
Cryptographic Operators                       False
Event Log Readers                             False
Certificate Service DCOM Access               False
Domain Computers                              False
Domain Controllers                            False
Schema Admins                                 False
Enterprise Admins                             False
Cert Publishers                               False
Domain Admins                                 False
Domain Users                                   True
Domain Guests                                 False
Group Policy Creator Owners                   False
RAS and IAS Servers                           False
Server Operators                              False
Account Operators                             False
Pre-Windows 2000 Compatible Access            False
Incoming Forest Trust Builders                False
Windows Authorization Access Group            False
Terminal Server License Servers               False
Allowed RODC Password Replication Group       False
Denied RODC Password Replication Group        False
Read-only Domain Controllers                  False
Enterprise Read-only Domain Controllers       False
DnsAdmins                                     False
DnsUpdateProxy                                False
Marketing                                      True
Research                                      False
Production                                    False
IT                                            False
demo                                          False

Description
-----------
Loads a list of SAMAccountNames from a text file and
examines their group membership.  It outputs
a list off all groups listed in Active Director with
a $True/$False value.  If the value is $True, all the
users in the list are members of that group.  If it
is false, at least one member of that list is not in
that group.



.NOTES
The Active Directory Module for PowerShell must be
Available

The input file must contain only SAMAccountNames.

Each line of the file must only contain one
SAMAccountName.


.LINK

#>
Function Compare-Group
{
param (
[Parameter(Position=0,Mandatory=$True)]$UserList,
[Switch]$ListAll
)


# Test to verify that the Active Directory module is
# available.
If ((Confirm-module ActiveDirectory) -eq $True)
{
# Import the Active Directory module.
   Import-Module ActiveDirectory -cmdlet Get-ADUser, Get-ADGroup,
Get-ADGroupMember
}
ELSE
{
Write-Host "Active Directory Module is not availible."
-ForegroundColor Red -BackgroundColor Yellow
Break
}

# Load list of users
Try {
$Users = Get-Content $UserList -ErrorAction Stop
}
Catch
{
# If the file or path is not correct or does not
   # Exist, Warn the user and stop execution.
   Write-Host "The file or path is not correct" -ForegroundColor Red
-BackgroundColor Black
BREAK
}

# Create an object of users names
$UserObj = @()
ForEach ($U in $Users)
{
$UObj = New-Object PSObject
$UObj | Add-Member NoteProperty -name Name -Value $U
$UserObj += $UObj
}


# Load list of Groups
$Groups = Get-ADGroup -Filter *


# Only show groups that all users in the list are
# members of.

$MatchAll = $True
If ($MatchAll = $True)
{
# Create a custom object to hold the Group
   # names.  Include a Boolean property to
   # be used to determine if a user is a member of
   # that group.

$GroupObj = @()

Foreach ($G in $Groups)
{
# Create an instance of a PSObject
       $Group = New-Object PSObject

# Add the name value from the group being
       # processed to the object.
       $Group | Add-Member NoteProperty -Name Name -Value $G.Name

# Add the Boolean value property to the object.
       $Group | Add-Member NoteProperty -Name UserPresent -Value $false

# Add this instance of the object to the group of objects.
       $GroupObj += $Group
}


# Cycle through each group and compare the members of
   # Each group.  If a member if in the group, set the
   # 'UserPresent' property to $True.  If not, set the
   # the value to $False.  Any group tat is marked $true
   # at the end of this process contains all the users from the
   # list.

ForEach ($G in $GroupObj)
{
# Get the list of user Names

$MemberList = Get-ADGroupMember $G.Name

# Loop through the list of users and determine
       # if they are members of the group.  If they
       # are, set the value of 'UserPresent' to $True
       # If not, set it to $False.

ForEach ($Member in $MemberList)
{

ForEach ($User in $Users)
{
# Format each variable that will be
                # tested to make sure there are no
                # carriage returns.  Also, make sure they
                # are of data type [String] and have
                # no leading or trailing spaces.
                $Testmember = ($Member.SamAccountName) -as [String]
$User = (($User -Replace "\n","") -as [String]).trim()



# Test to see if the user is a member of the
               # group.
               If ($User -ieq $Testmember)
{

If ($User -ne "")
{
# Set the UserPresent property to
                       # $True if the user and member
                       # properties match.
                       $G.UserPresent = $True
}

}
}

}



} # End of forEach ($G in $Groups)

} # End If ($MatchAll = $True)

# Send the output to the Pipeline.

# Send all the results to the pipeline if
# the user request it.
If ($ListAll -eq $True)
{
Write-Output $GroupObj
}

# Send only the groups that all users are
# members of to the pipeline by default.
If ($ListAll -eq $False)
{
ForEach ($obj in $GroupObj)
{
If ($Obj.UserPresent -eq $True)
{
Write-Output $Obj
}
}
}


}