Strange error with NewWebPage - SP 2010 Foundation - sharepoint

I'm having a strange issue here using the NewWebPage xml command in SP 2010 Foundation. The below code works does not work
cls
Write-Host "Production Manager v8.0 Deployment Utility" -ForegroundColor red
Write-Host ""
#Starting the script. Lets see if we can find the configuration and map files first.
Write-Host -NoNewline "Checking for the Configuration.xml, PageMap.xml and PageTemplate.xml files: " -ForegroundColor white
if((Test-Path "Configuration.xml") -and (Test-Path "PageMap.xml") -and (Test-Path "PageTemplate.xml"))
{
Write-Host "FOUND" -ForegroundColor green
}
else
{
Write-Host "NOT FOUND" -ForegroundColor red
Write-Host "Check for the necessary files and try again."
Write-Host ""
Write-Host ""
exit
}
Write-Host "Reading Configuration.xml"
[xml]$Configuration = Get-Content Configuration.xml
Write-Host "Reading PageMap.xml"
[xml]$PageMap = Get-Content PageMap.xml
Write-Host "Reading from Production Manager Site: "$Configuration.Configuration.SiteConfiguration.SiteURL
#Some variables necessary for the loop
$pageCreationLoopIterations = 0
$pageLayout = ""
$pageTitle = ""
$createPageCommand = '<?xml version="1.0" encoding="UTF-8"?><Method ID="0,NewWebPage"><SetList Scope="Request">' + $productionManagerLibrary.ID + '</SetList><SetVar Name="Cmd">NewWebPage</SetVar><SetVar Name="ID">New</SetVar><SetVar Name="Type">WebPartPage</SetVar><SetVar Name="WebPartPageTemplate">' + $pageLayout + '</SetVar><SetVar Name="Overwrite">true</SetVar><SetVar Name="Title">MyPage</SetVar></Method>';
#Beginning the loop
Write-Host "Running through the PageMap file"
foreach($Page in $PageMap.Pages.Page)
{
$web = Get-SPWeb $Configuration.Configuration.SiteConfiguration.SiteURL
$productionManagerLibrary = $web.Lists | Where { $_.Title -eq "Production Manager" }
$pageName = if($Page.SelectSingleNode("PageName")) { $Page.PageName } else { $Configuration.Configuration.PageConfiguration.DefaultPageName }
$pageLayout = if($Page.SelectSingleNode("PageLayout")) { $Page.PageLayout } else { $Configuration.Configuration.PageConfiguration.DefaultPageLayout }
Write-Host 'Creating Page ' $pageName
$web.ProcessBatchData($createPageCommand)
}
But this one works just fine every time I run it:
$url = "http://mpm8/mpm";
$listname = "Production Manager"
$web = Get-SPWeb $url
$pagesLibrary = $web.Lists | Where { $_.Title -eq "Production Manager" }
$pageLayout = 8
$cmd = '<?xml version="1.0" encoding="UTF-8"?><Method ID="0,NewWebPage"><SetList Scope="Request">' + $pagesLibrary.ID + '</SetList><SetVar Name="Cmd">NewWebPage</SetVar><SetVar Name="ID">New</SetVar><SetVar Name="Type">WebPartPage</SetVar><SetVar Name="WebPartPageTemplate">' + $pageLayout + '</SetVar><SetVar Name="Overwrite">true</SetVar><SetVar Name="Title">MyPage</SetVar></Method>';
$web.ProcessBatchData($cmd)
I really cannot see anything different between the two scripts. The error I get running the first one is:
<Result ID="0,NewWebPage" Code="-2130575350">
<ErrorText>Invalid URL Parameter.
The URL provided contains an invalid Command or Value. Please check the URL again. </ErrorText></Result>
Can you help me on this one? Maybe I cannot run this thing out a foreach loop? :(
Thanks!

You have set the $createPageCommand first (before the loop), then set the variables that it needs second (in the loop).
If you run this in the ISE and step through (ie debug it), you can see the variables and their values, otherwise simply emit the values of the variables to screen as you run through the loop to ensure it is setting them correctly.
So, in your example, place the $createPageCommand within the loop and after $productionManagerLibrary is set. Then, immediately before $web.ProcessBatchData($createPageCommand) you should emit the value of $createPageCommand to ensure it is OK.
I've only eye balled this without running it, but please us know if this is the reason!

Related

Powershell function in while loop doesn't output result first time but does output second time,twice

As you can see I have 5 options to select once the script runs. When I press 1, option 1 selected" gets printed but the function get_all_tags doesn't get called out and doesn't print list of tags. Second time around it prints the results from the function but repeats the result twice.
The weird thing about this is that the its inconsistent. I would run the script and in my first try pressing 1, sometimes, I would get the result from the function get_all_tags .When all the functions are tested on their own, it works perfectly fine. The while loop seems to have caused something irregular within and not sure how I can fix it.
$options=0
$iteration=0
while($options -ne 5)
{
$options = read-host -prompt "
Press
1. to search for all the tags running on Azure Virtual Machine(s)
2. to search for resource using tag name
3. to search for specific resource
4. to search for value of a tag name
5. to exit
"
if ($options -eq 1){
write-host "option 1 selected"
get_all_tags
#give option to exit or go back to the main menu
$iteration++
$iteration
}
elseif ($options -eq 2){
get_resource_with_tag_name $inputTagName
#give option to exit or go back to the main menu
}
elseif ($options -eq 3){
get_resource_tags $inputResource
#give option to exit or go back to the main menu
}
elseif ($options -eq 4){
get_keys_value $inputTagKey
#give option to exit or go back to the main menu
}
}
Function get_resource_tags($resourceName)
{
$inputResource = read-host -prompt 'Write a resource name you wish to search with all associated tags'
return (get-azresource -ResourceGroupName $inputResource).Tags
}
Function get_resource_with_tag_name($tagName){
$inputTagName = read-host -prompt 'Write a tag name you wish to search associated with resource'
return (get-AzResource -TagName $inputTagName).Name
}
Function get_all_tags{
return get-aztag
}
Function get_keys_value($tagKeyName){
$inputTagKey = read-host -prompt 'Write a tag name'
$result = (get-aztag -Detailed $inputTagKey).Values
$final = $result | ft -property #{n="Tag Value";e={$_.name}},count
return $final
}
PowerShell is an interpreter language as opposed to a compiler language. Hence, the location of your Functions is messing with your results. They should be declared before they are being called.
In your case, during the 1st run, the while loop is not aware of the functions defined below it. Once you run it completely, the functions are loaded in memory and hence, the second run will probably give you the intended results.
thanks #sid for responding and pointing out the difference. Despite having made the changes, Options 1 and 3 still do that same whilst 2 and 4 always print out results.
Function get_all_tags{
return get-aztag
}
Function get_resource_with_tag_name($tagName){
$inputTagName = read-host -prompt 'Write a tag name you wish to search associated with resource'
return (get-AzResource -TagName $inputTagName).Name
}
Function get_resource_tags($resourceName)
{
$inputResource = read-host -prompt 'Write a resource name you wish to search with all associated tags'
$iteration++
$iteration
return (get-azresource -ResourceGroupName $inputResource).Tags
}
Function get_keys_value($tagKeyName){
$inputTagKey = read-host -prompt 'Write a tag name'
$result = (get-aztag -Detailed $inputTagKey).Values
$final = $result | ft -property #{n="Tag Value";e={$_.name}},count
return $final
}
$options=0
$iteration=0
while($options -ne 5)
{
$options = read-host -prompt "
Press
1. to search for all the tags running on Azure Virtual Machine(s)
2. to search for resource using tag name
3. to search for specific resource
4. to search for value of a tag name
5. to exit
"
if ($options -eq 1){
write-host "option 1 selected"
get_all_tags
#give option to exit or go back to the main menu
}
elseif ($options -eq 2){
get_resource_with_tag_name $inputTagName
#give option to exit or go back to the main menu
}
elseif ($options -eq 3){
write-host "hello"
get_resource_tags $inputResource
#give option to exit or go back to the main menu
}
elseif ($options -eq 4){
get_keys_value $inputTagKey
#give option to exit or go back to the main menu
}
}

Export to csv after loop ends with powershell

I have the following powershell scripts that iterates through all list items and workflows, trying to find old running workflows
The logic is OK, but I need to be able to export to to csv with the columns
ListeItemUrl, ListItemName, Nr of Days Opened.
$web = get-spweb https://mysite.com/sites/billing
$list = $web.Lists["Bill Cycles"]
$count = 0
foreach($wf in $list.WorkflowAssociations)
{
if ($wf.Name -like "*Previous Version*")
{
Write-Host 'Bill Cycles with old workflow: ' $wf.Name
foreach($listitem in $list.Items)
{
if($listitem.ContentType.Name -eq "Bill Cycle")
{
$workflows = $listitem.Workflows
foreach($Workflow in $listitem.Workflows)
{
if($Workflow.AssociationId -eq $wf.Id)
{
$count = $count+1
Write-Host $listitem.Name
Write-Host 'https://mysite.com/sites/billing/'$listitem.Url.TrimStart();
Write-Host 'Workflow opened for: ' ((Get-Date) - $Workflow.Created).Days
}
}
}
}
}
}
Write-host 'Count: ' $count
Then with the exported file I can easily sort by nr of days and deliver the report I need.
Format your output as a csv - ListeItemUrl, ListItemName, NrofDaysOpened - and pipe it to Export-Csv cmdlet( you can find out more by running get-help Export-Csv). You will have to change Write-Host to Write-Output

Change List Field with Powershell in SharePoint Online

I'm attempting to change the field contents for multiple entries in a list. So far I've gotten to the point that I can edit the list, add columns really, but can't find anything on how to edit the field text. Here is what I have currently:
EDIT:
I've found a bunch of info for 2010 which isn't applicable but I've updated the code to almost get there. I'm getting 'null array' errors when I connect to the list now. I'm hopeful because I'm able to connect, but still can't get the field to change. I've updated my if statement as well to what is I believe a better format.
#Load necessary module to connect to SPOService
[System.Reflection.Assembly]::LoadWithPartialName("Microsoft.SharePoint.Client") | Out-Null
[System.Reflection.Assembly]::LoadWithPartialName("Microsoft.SharePoint.Client.Runtime") | Out-Null
#Login Information for script
$User = "user#email.com"
$Pass = "password"
$creds = New-Object System.Management.Automation.PSCredential($User, (ConvertTo-SecureString $Pass -AsPlainText -Force));
#Connect to SharePoint Online service
Write-Host "Logging into SharePoint online service." -ForegroundColor Green
Connect-SPOService -Url https://site-admin.sharepoint.com -Credential $creds
#Get the Necessary List
Write-Host "Getting the required list." -ForegroundColor Green
$WebUrl = 'https://site.sharepoint.com/'
$Context = New-Object Microsoft.SharePoint.Client.ClientContext($WebUrl)
$List = $Context.Web.Lists.GetByTitle("VacationRequestForm")
#Edit existing list items
$items = $List.items
foreach($item in $items)
{
if($item["Export Flag"] -eq "New")
{
Write-Host "Changing export flags to Complete." -ForegroundColor Green
$item["Export Flag"] = "Complete"
$item.Update()
}
}
Write-Host "Your changes have now been made." -ForegroundColor Green
I am guessing you have trimmed the script since you are missing things like defining $context and such. You don't have any ExecuteQuery() calls.
MSDN doc on SP 2013 CSOM List Item tasks, which has C# examples of what you need and can be translated to PowerShell.
It generally looks like you have everything but if you could include your whole script I can try and run your script directly.
EDIT: with the updates here is the code that you need
#Load necessary module to connect to SPOService
[System.Reflection.Assembly]::LoadWithPartialName("Microsoft.SharePoint.Client") | Out-Null
[System.Reflection.Assembly]::LoadWithPartialName("Microsoft.SharePoint.Client.Runtime") | Out-Null
#Login Information for script
$User = "user#email.com"
$Pass = "password"
$WebUrl = "https://site.sharepoint.com/"
#Connect to SharePoint Online service
Write-Host "Logging into SharePoint online service." -ForegroundColor Green
$Context = New-Object Microsoft.SharePoint.Client.ClientContext($WebUrl)
$Context.Credentials = New-Object Microsoft.SharePoint.Client.SharePointOnlineCredentials($User, (ConvertTo-SecureString $Pass -AsPlainText -Force))
#Get the Necessary List
Write-Host "Getting the required list." -ForegroundColor Green
$List = $Context.Web.Lists.GetByTitle("VacationRequestForm")
$Query = [Microsoft.SharePoint.Client.CamlQuery]::CreateAllItemsQuery(100);
$Items = $List.GetItems($Query);
$Context.Load($Items);
$Context.ExecuteQuery();
#Edit existing list items
foreach($item in $Items)
{
if($item["Export_x0020_Flag"] -eq "New")
{
Write-Host "Changing export flags to Complete for Id=$($item.Id)." -ForegroundColor Green
$item["Export_x0020_Flag"] = "Complete"
$item.Update()
$Context.ExecuteQuery();
}
}
Write-Host "Your changes have now been made." -ForegroundColor Green
You had a space in your Export Flag name and SharePoint will not have that in the name of the field. By default it will replace that with a _x0020_ string. This value will be based on the first name of the field. So if you change this field name in the future, you will still refer to it as 'Export_x0020_Flag' in this script. I am doing the .ExecuteQuery() for each update but you could do this once at the end of the loop. There is also the limit of 100 records in the query. If you only want records with "New" you should change the CamlQuery to just pull those records back.

PowerShell - Enumerating through a collection and change the collection

How it is posible to fix this script?
Yes, I´m changing the collection in the foreach loop and this is the reason for this error.
An error occurred while enumerating through a collection: Collection was modified; enumeration operation may not execute..
At C:\Users\user\Documents\PowerShell\ChangeAllListsV2.ps1:47 char:20
+ foreach <<<< ($list in $webLists)
+ CategoryInfo : InvalidOperation: (Microsoft.Share...on+SPEnumerator:SPEnumerator) [], RuntimeException
+ FullyQualifiedErrorId : BadEnumeration
#Script change in all lists the required field property "testfield" to false
#Part 0 - Configuration
$urlWebApp = "http://dev.sharepoint.com"
$countFound = 0
$countList = 0
$countFoundAndChange = 0
#Part 1 - PreScript
$snapin = Get-PSSnapin | Where-Object {$_.Name -eq "Microsoft.SharePoint.Powershell"}
if ($snapin -eq $null)
{
Write-Host “Loading SharePoint Powershell”
Add-PSSnapin Microsoft.SharePoint.Powershell
}
#Part 2 - Script
$webApp = Get-SPWebApplication $urlWebApp
#$webApp | fl
$webAppSites = $webApp.sites
foreach($site in $webAppSites)
{
Write-Host "***********************************************************************"
Write-Host "Found site: " $site -foreground blue
$siteAllWebs = $site.AllWebs
foreach($web in $siteAllWebs)
{
Write-Host "Found web: " $web -foreground blue
#$web | fl
$webLists = $web.Lists
foreach($list in $webLists)
{
$countList ++
Write-Host "Found list: " $list -foreground blue
#Change list property
$field = $Null
$field = $list.Fields["testfield"]
if($field){
Write-Host "Field found: " $list -foreground green
#Write-Host "in web: " $web -foreground green
$countFound ++
try{
if($field.Required)
{
#######################################################
$field.Required = $False
$field.Update()
#######################################################
$field = $Null
Write-Host "Done!: Change list: " $list -foreground green
$countFoundAndChange ++
}else{
Write-Host "Already!: Change list: " $list -foreground green
}
}
catch{
$field = $Null
Write-Host "Error!: Change list: " $list -foreground red
Write-Host "in web: " $web -foreground red
$_
}
}
}
}
}
Write-Host "Found lists: " $countList
Write-Host "Found lists with column [testfield]: " $countFound
Write-Host "Change lists with column [testfield]: " $countFoundAndChange
The SPListCollection tends to modify the collection when updating its properties (fields, event receivers, etc.). You can use a for-loop instead:
for ($i = 0; $i -lt $webLists.Count; $i++)
{
$list = $web.Lists[$i];
# ...
}
I know this is a pretty old thread. This is for anybody ending up to this page looking for an answer.
The idea is, like other answers suggest, to copy the collection (using the clone() method) to another and iterate "another" and modify the original variable inside the loop without having to use for in place of foreach:
A collection of type ArrayList:
[System.Collections.ArrayList]$collection1 = "Foo","bar","baz"
$($collection1.Clone()) | foreach {
$collection1.Remove("bar")
}
Output:
PS H:\> $collection1
Foo
baz
A collection of type Hashtable:
[System.Collections.Hashtable]$collection2 = #{
"Forum" = "Stackoverflow"
"Topic" = "PowerShell"
}
$($collection2.Clone())| foreach {
$collection2.Remove("Forum")
}
Output:
PS H:> $collection2
Name Value
---- -----
Topic PowerShell
And, a basic array:
[System.Array]$collection3 = 1, 2, 3, 4
$($collection3.Clone()) | foreach {
$collection3[$collection3.IndexOf($_)] = 10
}
Output:
PS H:\> $collection3
10
10
10
10
As long as your collection is not of fixed size.
You can try copying the collection you're currently iterating on to another collection (an array or a list) and then iterate on that new collection.
Something like this:
$collection = #(1, 2, 3, 4)
$copy = #($collection)
$collection[0] = 10
$collection -join " "
$copy -join " "
The code above gives the following output:
10 2 3 4
1 2 3 4
Note that the $copy variable refers to a different collection.
Check: http://soreddymanjunath.blogspot.in/2014/07/collection-was-modified-enumeration.html
Here is anonther example for same issue
if($web.IsMultilingual -eq $true )
{
foreach($cul in $web.SupportedUICultures)
{
if($cul.LCID -ne $webCul.LCID -and $cul.LCID -ne "1033")
{
$web.RemoveSupportedUICulture($cul)
}
}
$web.Update()
}
for the first time it will go through the loop foreach will remove supported culture for frist time, when it comes to loop for the second iteration then it will throw you the exception “Collection was modified; enumeration operation may not execute”,
Solution to Above problem is to Store to values to modified in a Arraylist and try to modify which will fix the problem, Here i am storing Arraylist called enumcul and inserting values into it and modifying it...
$enumcul=New-Object Collections.ArrayList
$i=0
if($web.IsMultilingual -eq $true )
{
foreach($cul in $web.SupportedUICultures)
{
if($cul.LCID -ne $webCul.LCID -and $cul.LCID -ne "1033")
{
$enumcul.Insert($i, $cul)
$i=$i+1
}
}
foreach( $k in $enumcul)
{
$web.RemoveSupportedUICulture($k)
$web.Update()
}

Active Directory Filter memberof

I am trying to get all of the CN's out of active directory in order to populate groups based on that name into Sharepoint Services. I can list the "memberof" section but I can not seem to split it using split(",")
$Dom = 'LDAP://OU=External,OU=Users,OU=HomeOffice,DC=mydoman,DC=com'
$Root = New-Object DirectoryServices.DirectoryEntry $Dom
$i=0
# Create a selector and start searching from the Root of AD
$selector = New-Object DirectoryServices.DirectorySearcher
$selector.SearchRoot = $root
$adobj= $selector.findall() |`
where {$_.properties.objectcategory -match "CN=Person"}
foreach ($person in $adobj){
$prop=$person.properties
$i++
Write-host "$($prop.department) - $($prop.sn), $($prop.givenname)"
Write-host $person.properties["memberof"]
}
"Total $i"
Now I get everything I need, but I need some way to filter only the CN's out...
As a general rule, write-host is not the best way to generate output. Ideally, you want to emit objects out of your function and let PowerShell do the formatting for you. This is the more "pipeline friendly" way of doing things. In this case, if you had a function Get-GroupMembers you could pipe it to something like
Get-Person | ft CN
The trick is creating a new object and adding properties to it, or just emitting the DirectoryServices object you are pulling already. To create a new custom object you can do the following:
$obj = new-object psobject
$obj | add-member -membertype noteproperty name $PropName -value $valueToStore
People can use your function and pipe it to format-table, format-list, select-object, group-object, sort-object and a variety of other things. Keith Hill's Effective PowerShell has a great chapter on Output that you might find helpful.
There is also an article by Don Jones on using objects instead of text that is quite good as well.
test1.ps1
#Connet using LDAP
$Dom = 'LDAP://OU=External Accounts,OU=Users,OU=The Office,DC=mydomain,DC=com'
$Root = New-Object DirectoryServices.DirectoryEntry $Dom
#Integer for the loop
$i=0
# Create a selector and start searching from the Root of AD
$selector = New-Object DirectoryServices.DirectorySearcher
$selector.SearchRoot = $root
#Find the Groups
$adobj= $selector.findall() |`
where {$_.properties.objectcategory -match "CN=Person"}
foreach ($person in $adobj){
$prop=$person.properties
$i++
#Write-host "$($prop.department) - $($prop.sn), $($prop.givenname)" -foregroundcolor Magenta
$test = $person.properties["memberof"]
ForEach-Object {
$test`
-replace "CN=OLDLEGACYGROUP",""`
-replace "CN=",""`
-replace ",OU=Sales",""`
-replace ",OU=Some Groups",""`
-replace ",OU=Groups","" `
-replace ",OU=The Office","" `
-replace ",DC=mydomain","" `
-replace ",DC=com","" `
-replace ",","`r`n"
}
}
test2.ps1
# Lets start with a clean slate :)
Clear
# Lets reference the assembly / GAC that we need for this
#region
[Void][System.Reflection.Assembly]::LoadWithPartialName("Microsoft.SharePoint")
$SPSite = New-Object Microsoft.SharePoint.SPSite("https://myintranetorextranetsite.myfqdn.com")
$OpenWeb = $SpSite.OpenWeb("/")
#endregion
# Add some eye candy :)
# region
# I really wanted some old school thing in here :)
write-host " _ ____ ____ " -foregroundcolor Magenta
write-host " / \ | _ \ / ___| _ _ _ __ ___ " -foregroundcolor Magenta
write-host " / _ \ | | | |____\___ \| | | | '_ \ / __|" -foregroundcolor Magenta
write-host " / ___ \| |_| |_____|__) | |_| | | | | (__ " -foregroundcolor Magenta
write-host "|_/ \_\____/ |____/ \__, |_| |_|\___|" -foregroundcolor Magenta
write-host " |___/ " -foregroundcolor Magenta
Write-Host " Version 2.0" -foregroundcolor Red
Write-Host " Build 2009 09-11 21:30" -foregroundcolor Red
Write-host " Created by Mitchell J. Skurnik" -foregroundcolor Red
#endregion
# Create the stopwatch
#region
[System.Diagnostics.Stopwatch] $sw;
$sw = New-Object System.Diagnostics.StopWatch
$sw.Stop()
$sw.Start()
#endregion
# Function to control Adding groups
function creategroup
{
param ([string] $siteurl = "https://myintranetorextranetsite.myfqdn.com")
$site = New-Object Microsoft.SharePoint.SPSite($siteurl)
$web = $site.RootWeb;
$group = $currentgroup;
$perm = "Read";
$owner = "jdoe";
if ($owner -eq "") { $owner = $web.CurrentUser.LoginName }
$exists = $web.SiteGroups | where { $_.Name -eq $group }
if ($exists -eq $null)
{
# Create group
$web.SiteGroups.Add($group, $web.EnsureUser($owner), $null, "");
# Give permissions to the group
$assign = New-Object Microsoft.SharePoint.SPRoleAssignment($web.SiteGroups[$group]);
$assign.RoleDefinitionBindings.Add($web.RoleDefinitions[$perm])
$web.RoleAssignments.Add($assign)
Write-Host -ForegroundColor green "Creating sharepoint group - " $currentgroup;
}
$site.Dispose();
}
# Function to add users to the specified group
function addUser
{
# Open a connection to the sharepoint site and then select the sub site you want
$themail = $prop.mail
$thedisplay = $prop.displayname
# If there are accounts that dont have some info lets populate it
if ($themail -eq "")
{
$themail = "testaccount#myfqdn.com"
}
if ($thedisplay -eq "")
{
$thedisplay = "Account, Test"
}
if ($themail -eq $null)
{
$themail = "testaccount#myfqdn.com"
}
if ($thedisplay -eq $null)
{
$thedisplay = "Account, Test"
}
$TheNewGroup = $OpenWeb.SiteGroups | Where-Object {$_.Name -match $currentGroup}
$TheNewGroup.AddUser("NTAMR\" + $prop.samaccountname,$themail,$prop.displayname,"")
#write-host "Added: " $thedisplay -foregroundcolor Red
}
# Function to remove people - be careful using this script :(
# Also not done
function removeUser
{
#$TheNewGroup = $OpenWeb.SiteGroups | Where-Object {$_.Name -match $currentGroup}
#$TheNewGroup.AddUser("NTAMR\" + $prop.samaccountname,$themail,$prop.displayname,"")
#$TheNewGroup.Remove($LoginToDel)
}
# Now onto the real stuff
Write-host "Searching for Groups" -foregroundcolor Green
# Clear out the existing text file so we have a clean slate
$file = New-Item -type file "C:\location\to\my\folder\allGroups.txt" -Force
# Execute the Group Dump Script
C:\location\to\my\folder\test.ps1 | Out-File -filepath "C:\location\to\my\folder\allGroups.txt" -append
# Clean up the list by removing duplicates and sorting everything
$TextFile = $TextFile = "C:\Powershell\allGroups.txt"
$NewTextFile = "C:\Powershell\allGroups - Sorted.txt"
GC $TextFile | Sort | GU > $NewTextFile
# Use LDAP to connect to Active Directory
#region
$Dom = 'LDAP://OU=External Accounts,OU=Users,OU=The Office,DC=mydomain,DC=com'
$Root = New-Object DirectoryServices.DirectoryEntry $Dom
#endregion
# Create a selector and start searching from the Root of AD
#region
$selector = New-Object DirectoryServices.DirectorySearcher
$selector.SearchRoot = $root
#endregion
# Integer to compare file length
$c=0
# Get the Group text file's length and write to scree and variable
$fileLength = [System.IO.File]::ReadAllText($NewTextFile).Split("`n").Count
Write-Host "Found " $fileLength "Groups in Active Directory" -foregroundcolor Magenta
# Integer for thumbing through 'memberOf' in active directory
$d = 0
# Integer for the amount of of users found
$f = 0
# Start a while loop where we read through the entire groups text file
while ($c -le $fileLength)
{
# Increment the line number for the next pass through
$c++
# Grab the first line of text from the groups file (Really the 0th line) and then tell the user
$currentGroup = (Get-Content $NewTextFile)[$c]
# Create the group
CreateGroup
#Write-Host "Created Group: " $currentGroup -foregroundcolor Red
#
Write-host $c "/" $fileLength "`t" $currentGroup -foregroundcolor Red
# Query Active directory and force some commands
$adobj= $selector.findall() | where {$_.properties.objectcategory -match "CN=Person"}
foreach ($person in $adobj)
{
# Variable for the different properties to reduce fatigue
$prop=$person.properties
# The Department
$department = $prop.department
# Sir Name
$sn = $prop.sn
# Given Name
$gn = $prop.givenname
$un = $prop.samaccountname
# Assign the really long memberof to a variable
$memberof = $person.properties["memberof"]
# Length of memberof
$memberofcount = $test.Count
# Loop for each group the member is in
while ($d -le $memberof.Count)
{
$blah = ForEach-Object{`
$memberof[$d]`
-replace "CN=OLDLEGACYGROUP",""`
-replace "CN=",""`
-replace ",OU=Sales",""`
-replace ",OU=Some Groups",""`
-replace ",OU=Groups","" `
-replace ",OU=The Office","" `
-replace ",DC=mydomain","" `
-replace ",DC=com","" `
}
# Incriment the d
$d++
# Is that user in the group?
if ($blah -eq $currentGroup)
{
# Hey look we found somebody in that group :)
Write-host "`t`t`t" $un -foregroundcolor Magenta
addUser
$f++
}
#elseif ($blah -ne $currentGroup)
#{
# removeUser
#}
else
{
# Oh noes...nobody is in that group...that is strange
}
}
# Are we at the end of what the user has
if ($d -ge $memberofs.Count)
{
# Looks like we are :)
$d=0
}
}
# Display amount of users found
#Write-Host "`t`t`t" $f " user(s) found"
$f = 0
}
# Stop Watch
$sw.Stop()
# Write the compact output to the screen
write-host "Updated in Time: ", $sw.Elapsed.ToString()
#This space is saved for future development

Resources