I need to scan Active Directory and pipe the information into a local admin checking script. But for some reason this script keeps failing. It fails at
$Group = $computer.psbase.children.find(”Administrators”)
Here is the script
################################################
#Start looking for windows 10 & computers 7 #
################################################
$root = {Get-ADComputer -Filter * | Where-Object {$_.Name -like "win10*"} | Select -Property Name
Get-ADComputer -Filter * | Where-Object {$_.Name -like "*win7"} | Select -Property Name}
foreach ($server in $root)
{
$computer = [ADSI](”WinNT://” + "$server" + “,computer”)
$Group = $computer.psbase.children.find(”Administrators”)
$members = ($Group.psbase.invoke(”Members”) | %{$_.GetType().InvokeMember(”Adspath”, ‘GetProperty’, $null, $_, $null)}) - replace ('WinNT://DOMAIN/' + $server + '/'), '' -replace ('WinNT://DOMAIN/', 'DOMAIN\') -replace ('WinNT://', '')
$members }
You were looking at the wrong line. It's the $members = line that it's complaining about. You have two spaces between the hyphen and your first "replace":
- replace ('WinNT://DOMAIN/' + $server + '/')
There shouldn't be any spaces there. Try this:
$root = {Get-ADComputer -Filter * | Where-Object {$_.Name -like "win10*"} | Select -Property Name
Get-ADComputer -Filter * | Where-Object {$_.Name -like "*win7"} | Select -Property Name}
foreach ($server in $root)
{
$computer = [ADSI](”WinNT://” + "$server" + “,computer”)
$Group = $computer.psbase.children.find(”Administrators”)
$members = ($Group.psbase.invoke(”Members”) | %{$_.GetType().InvokeMember(”Adspath”, ‘GetProperty’, $null, $_, $null)}) -replace ('WinNT://DOMAIN/' + $server + '/'), '' -replace ('WinNT://DOMAIN/', 'DOMAIN\') -replace ('WinNT://', '')
$members
}
If you aren't already, try using the Windows PowerShell ISE, which is included in Windows, for writing PowerShell scripts. It will highlight simple syntax errors like that.
Related
I am running the below script and it is causing exception of type 'system.outofmemoryexception' was thrown
I believe that it is due to the #Results array growing past the 2gb allocated to windows shell. Is there possibly a way to iterate through the results, or am I stuck with allocating more memory (which could ultimately be a lot...)?
$Path = "path to output"
### Get all PF
$publicFolders = Get-PublicFolder "Public Folder Name" -Recurse -resultsize unlimited | Select-Object *
### Array to contain results
$results = #()
###Begin looping through each PF and grab each user/group with AccessRights to that folder
$final = ForEach($pf in $publicFolders){
$perms = Get-PublicFolderClientPermission -Identity $pf.Identity | Where-Object {$_.User -notmatch "Default|Anonymous|S-X-X-XX"}
Foreach($perm in $perms){
$temp = [PSCustomObject]#{
MailFolderName = $pf.Identity
UserWithPerms = $perm.User
AccessRights = $perm | Select-Object -ExpandProperty AccessRights
}
$results += $temp
}
}
$final | Export-Csv $path -NoTypeInformation
Am I barking up the wrong tree?
Thanks in advance.
Use the ForEach-Object cmdlet instead of a foreach(){} loop statement for the outer loop - this way you can start piping the output to Export-Csv immediately instead of buffering it in an array:
$publicFolders |ForEach-Object {
$pf = $_
$perms = Get-PublicFolderClientPermission -Identity $pf.Identity | Where-Object {$_.User -notmatch "Default|Anonymous|S-X-X-XX"}
Foreach($perm in $perms){
[PSCustomObject]#{
MailFolderName = $pf.Identity
UserWithPerms = $perm.User
AccessRights = $perm | Select-Object -ExpandProperty AccessRights
}
}
} | Export-Csv $path -NoTypeInformation
Alternatively, flush the partial set of results to file after enumerating the permissions for each folder:
ForEach($pf in $publicFolders){
$perms = Get-PublicFolderClientPermission -Identity $pf.Identity | Where-Object {$_.User -notmatch "Default|Anonymous|S-X-X-XX"}
$results = Foreach($perm in $perms){
[PSCustomObject]#{
MailFolderName = $pf.Identity
UserWithPerms = $perm.User
AccessRights = $perm | Select-Object -ExpandProperty AccessRights
}
}
# flush the buffer before moving to the next set of permissions
$results |Export-Csv $path -NoTypeInformation -Append
}
i have a simple Array, created with the following Content (loop not shown)
$tmpArray += $AlarmgroupIndexString + ";" + $LanguageIDString + ";" + $ID_string + ";" + $_.Value
Is there a possibility to add the Content to a multidimensional Array?
I'll have to filter the entries later. With this setup, that's not possible.
I have made an attempt with the help of
$list = ConvertFrom-Csv $tmpArray -Header "GroupID", "Language", "TextID", "Text" -Delimiter ";"
$list | Sort-Object -Property GroupID, Language, TextID#
Unfortunately the conversion to excel did not result in a column Separation...
Please find my Code here
foreach ($file in $fileNames) {
$Content = [xml](Get-Content -Path $file.FullName)
$ns = New-Object System.Xml.XmlNamespaceManager($Content.NameTable)
$ns=#{DEF="http://br-automation.co.at/AS/VC/Project"}
$AlarmgroupIndex = Select-Xml -Xml $Content -XPath "//DEF:Property[contains(#Name,'Index')]" -namespace $ns | select -ExpandProperty node
$AlarmgroupIndexString = $AlarmgroupIndex.Value
$AlarmgroupLanguageText = Select-Xml -Xml $Content -XPath "//DEF:TextLayer" -namespace $ns | select -ExpandProperty node
$AlarmgroupIndexMap = Select-Xml -Xml $Content -XPath "//DEF:Index" -namespace $ns | select -ExpandProperty node
$LUT =#{}
$AlarmgroupIndexMap | foreach{
$LUT.($_.ID) = $_.Value
}
$tmpArray =#()
$AlarmgroupLanguageText | foreach{
$LanguageIDString = $_.LanguageId
$AlarmgroupTextLayer = Select-Xml -Xml $Content -XPath "//DEF:TextLayer[#LanguageId='$LanguageIDString']/DEF:Text" -namespace $ns | select -ExpandProperty node
$AlarmgroupTextLayer | foreach{
if($LUT.ContainsKey($_.ID))
{
$ID_string = $LUT[$_.ID]
}
$tmpArray += $AlarmgroupIndexString + ";" + $LanguageIDString + ";" + $ID_string + ";" + $_.Value
}
$LanguageIDString=""
}
$tmpArray | Out-File "$rootPath\test.txt" -Append -Encoding utf8
$list = ConvertFrom-Csv $tmpArray -Header 'GroupID', 'Language', 'TextID', 'Text' -Delimiter ";"
$list | Sort-Object -Property GroupID, Language, TextID
}
TIA
First of all:
$AlarmgroupIndexString + ";" + $LanguageIDString + ";" + $ID_string + ";" + $_.Value is not an array but a string (with sub-strings separated by semicolons)
Try to avoid using the increase assignment operator (+=) to create a collection (or a string) as it is exponential expensive (meaning that the cost will increase with each iteration).
It is a pity that you not showing more details about the loop as the result of your question actually depends how you initialize the $tmpArray variable:
If you start with a string ($tmpArray = '') or $Null it will continue to append to that string.
If you start with a string ($tmpArray = #()) it will continue to append the array (which is probably where you looking for).
If you going to use ConvertFrom-Csv you might also consider to start with a string and separate each row with a newline (e.g. ... + $_.Value + "`r`n")
Anyways, it is also not a good idea to use ConvertFrom-Csv to build a collection of PowerShell objects (for one reason: it will convert all the values to a string), the correct PowerShell way to do this is:
$List = 1..3 | Foreach-Object { # replace 1..3 with your enumerator
[pscustomobject]#{
AlarmIndex = $AlarmgroupIndexString
LanguageIndex = $LanguageIDString
ID = $ID_string
Value = $_.Value
}
}
}
Update based on the added information in the question:
I am not sure what exactly your application is supposed to do, but the loop should be something like:
$list = $AlarmgroupLanguageText | foreach {
$LanguageIDString = $_.LanguageId
$AlarmgroupTextLayer = Select-Xml -Xml $Content -XPath "//DEF:TextLayer[#LanguageId='$LanguageIDString']/DEF:Text" -namespace $ns | select -ExpandProperty node
$AlarmgroupTextLayer | foreach{
if($LUT.ContainsKey($_.ID))
{
$ID_string = $LUT[$_.ID]
}
[pscustomobject]#{
GroupID = $AlarmgroupIndexString
Language = $LanguageIDString
TextID = $ID_string
Text = $_.Value
}
}
}
$list | Sort-Object -Property GroupID, Language, TextID
I will suggest you to have a quick look on this article: https://www.andreasbijl.com/powershell-create-collections-of-custom-objects/
You can generate the list you want using the example described in the link above. For your case it should look similar to this:
$list = New-Object System.Collections.ArrayList
your_foreach_loop
{
$temp = New-Object System.Object
$temp | Add-Member -MemberType NoteProperty -Name "GroupID" -Value $AlarmgroupIndexString
$temp | Add-Member -MemberType NoteProperty -Name "Language" -Value $LanguageIDString
$temp | Add-Member -MemberType NoteProperty -Name "TextID" -Value $ID_string
$temp | Add-Member -MemberType NoteProperty -Name "Text" -Value $_.Value
$list.Add($temp)
}
Trying to automate our font installation process for new PCs.
To install fonts, Windows adds the .ttf, .otf, etc. file to C:\Windows\Fonts and then creates a corresponding registry key in HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Fonts. A typical registry key would look like this:
Arial (TrueType) | Arial.ttf
To automate this, I've made two arrays using Get-ChildItem:
$names = Get-ChildItem -Path "C:\corp\install\fonts" | Select-Object name | Out-String | ForEach-Object {$_ -Replace "----","" ` -Replace "Name","" ` -Replace ".otf","" ` -Replace ".ttf","" } | ForEach-Object { $_.Trim() }
$files = Get-ChildItem -Path "C:\corp\install\fonts" | Select-Object name | Out-String | ForEach-Object {$_ -Replace "----","" ` -Replace "Name","" } | ForEach-Object { $_.Trim() }
Each $name in $names will be the name of the registry key, and each $file in $files will be the data for that registry key.
How would I go about doing this? I've attempted to use hash tables, PSObjects, nested ForEach loops, all to no avail. I have had difficulty finding anything on here and elsewhere that matches this situation exactly.
Error checking is not really necessary since there will always be a corresponding value.
REVISED FINAL SOLUTION:
Write-Host "Installing corporate fonts..."
Copy-Item -Path "C:\corp\install\fonts\*" -Destination "C:\Windows\Fonts" -Force -Recurse
$fontList = #()
$fonts = Get-ChildItem "C:\corp\install\fonts" | Select-Object -ExpandProperty Name
ForEach ( $font in $fonts ) {
$fontList += [PSCustomObject] #{
Name = $font -Replace ".otf","" ` -Replace ".ttf",""
File = $font
} |
ForEach-Object {
New-ItemProperty -Path "HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Fonts" -Name $_.Name -Value $_.File
}
}
I must admit I don't fully understand your question so forgive me if this response is way off base, but it this what you're looking for? A table with both pieces of data in one?
Function CreateVariables {
$namevariables = #()
$filenames = ( Get-ChildItem "C:\corp\install\fonts" ).name
Foreach ( $name in $filenames ){
$namevariables += [PSCustomObject] #{
Name = $name -Replace "----","" ` -Replace "Name","" ` -Replace ".otf","" ` -Replace ".ttf",""
File = $name -Replace "----","" ` -Replace "Name",""
}
}
Return $namevariables
}
CreateVariables
Piping both name and value to set-itemproperty seem impossible. Foreach-object seems the way to go.
$path = 'hklm:\software\microsoft\windows nt\currentversion\fonts'
[pscustomobject]#{name='a name';value='a value'} |
foreach { set-itemproperty $path $_.name $_.value -whatif }
What if: Performing the operation "Set Property" on target "Item: HKEY_LOCAL_MACHINE\software\microsoft\windows nt\currentversion\fonts Property: a name".
You may prefer using this vbscript-like method to install fonts:
https://www.mondaiji.com/blog/other/it/10247-windows-install-fonts-via-command-line
I have a string array $Exclude which I want to put into a filter in a Get-WMIObject cmdlet. I have added it at the end but it does not work.
How can I filter out the services that are listed in that array?
$ServicesToExclude = "RemoteRegistry,CpqNicMgmt"
$Exclude = $ServicesToExclude.split(",")
$Services = Get-WmiObject -Class Win32_Service -Filter {State != 'Running' and StartMode = 'Auto' and Name -ne $Exclude}
$Result = foreach ($Service in $Services.Name)
{
Get-ItemProperty -Path "HKLM:\SYSTEM\CurrentControlSet\Services\$Service" |
Where-Object {$_.Start -eq 2 -and $_.DelayedAutoStart -ne 1}|
Select-Object -Property #{label='ServiceName';expression={$_.PSChildName}} |
get-Service
}
If ($Result.count -gt 0){
$Displayname = $Result.displayname
[string] $Line = "`n-----------------------------------------"
$Api.LogScriptEvent( 'Stopped_Auto_Services.ps1',1234,4,"`nStopped Automatic Services$Line `n$($Displayname)")
Filtering an array out of a list is not done on the WMI side. Instead, you should use Where-Object to filter out those services which name is contained in $Exclude.
$Services = Get-WmiObject -Class Win32_Service -Filter {State != 'Running' and StartMode = 'Auto'} |
Where-Object {$Exclude -notcontains $_.Name}
WMI queries do not work well with arrays and need to be done a different way. If you want to keep the filtering on the server side, you can do some work prior to running the command by creating a filter string as shown here:
$Exclude = "RemoteRegistry","CpqNicMgmt"
$StringBuilder = New-Object System.Text.StringBuilder
[void]$StringBuilder.Append("State != 'Running' AND StartMode = 'Auto' AND ")
[void]$StringBuilder.Append("($(($Exclude -replace '^(.*)$','Name != "$1"') -join ' AND '))")
$Query = $StringBuilder.ToString()
$Services = Get-WmiObject -Class Win32_Service -Filter $Query
There may be better ways to accomplish this, but this was the first thing that I could think of to accomplish the goal of your question.
Basicly i want to find inactive users so im using a foreach loop in a search base,
Now im trying to impliment looking at several OU's winthin an array at the start.
So this is what i was trying...
$OU=#("OU Path 1",
"OU Path 2",
"OU Path 3")
$OU | ForEach ($user in (Get-ADUser -SearchBase $_ -filter {(lastlogondate -notlike "*" -OR lastlogondate -le $90days) -AND (passwordlastset -le $90days) -AND (enabled -eq $True)} -Properties lastlogondate, passwordlastset | Select-Object name, lastlogondate, passwordlastset, samaccountname))
{
....
and getting the error....
At line:18 char:22
+ $OU | ForEach ($user in (Get-ADUser -SearchBase $_ -filter {(lastlogondate -notl ...
+ ~~ Unexpected token 'in' in expression or statement. At line:18 char:21
+ $OU | ForEach ($user in (Get-ADUser -SearchBase $_ -filter {(lastlogondate -notl ...
+ ~ Missing closing ')' in expression. At line:18 char:293
+ ... samaccountname))
+ ~ Unexpected token ')' in expression or statement.
+ CategoryInfo : ParserError: (:) [], ParentContainsErrorRecordException
+ FullyQualifiedErrorId : UnexpectedToken
This Works Fine
$SearchBase1 = "OU1"
$SearchBase2 = "OU2"
$SearchBase3 = "OU3"
ForEach ($user in(Get-ADUser -SearchBase $SearchBase1 -filter {(lastlogondate -notlike "*" -OR lastlogondate -le $90days) -AND (passwordlastset -le $90days) -AND (enabled -eq $True)} -Properties lastlogondate, passwordlastset | Select-Object name, lastlogondate, passwordlastset, samaccountname))
{
The problem is that you are trying to created a nested ForEach loop, and forgot the first part of the loop. Here, you want to pipe $OU into a ForEach loop, and within that ForEach loop create another loop based on the current object of the first ForEach loop.
$OU | ForEach{
ForEach ($user in (Get-ADUser -SearchBase $_ -filter {(lastlogondate -notlike "*" -OR lastlogondate -le $90days) -AND (passwordlastset -le $90days) -AND (enabled -eq $True)} -Properties lastlogondate, passwordlastset | Select-Object name, lastlogondate, passwordlastset, samaccountname))
{
<Do Stuff>
} #End inner ForEach Loop for current OU
}