Powershell variable doesn't contain all the objects - arrays

I got the following variable $listofusers which returns the below objects in two columns:
SourceUser DestinationUser
---------- ---------------
username1#legacy.company.corp username1#modern.company.corp
username2#legacy.company.corp username2#modern.company.corp
username3#legacy.company.corp username3#modern.company.corp
username4#legacy.company.corp username4#modern.company.corp
I now need to process this list of users in a foreach loop. I have tried so far the following but without luck yet:
$Results = ForEach ($User in $listofusers) {
Write-Host "Processing SourceUser $($User.SourceUser)"
Write-Host "Processing DestinationUser $($User.DestinationUser)"
#Assign the content to variables
$SourceUsers = $User.SourceUser
$DestinationUsers = $User.DestinationUser
}
It only returns me the last line of the objects:
$SourceUsers
RETURN ONLY: username4#legacy.company.corp
$DestinationUsers
RETURN ONLY: username4#modern.company.corp
How can I add all the objects in the variable $listofusers for further processing?
UPDATE:
I am trying to achieve the following that's why I have broken the association in listofusers
$SourceUser = #()
$DestinationUser = #()
$Results = ForEach ($User in $listofusers)
{
Write-Host "Processing SourceUser $($User.SourceUser)"
Write-Host "Processing DestinationUser $($User.DestinationUser)"
#Assign the content to variables
$SourceUser += $User.SourceUser
$DestinationUser += $User.DestinationUser
#Cannot get that variables working yet
$sourceusername, $sourcedomain = $SourceUser -split ("#")
$DestinationUsername, $destinationDomain = $DestinationUser -split ("#")
$SourceAccount = Get-ADUser $sourceusername -server $sourcedomain -Properties objectSid
$TargetAccount = Get-ADUser $DestinationUsername -Server $destinationDomain
}
Is there any better way to achieve that and get those variables to that point?
NEW UPDATE:
The purpose of the script would be to achieve the following cmdlets for processing ad objects:
#get the objectSid of the source account
$objectSid = $SourceAccount.objectSid
#copy source account objectSid to target account msExchMasterAccountSid
$TargetAccount | Set-ADUser -Replace #{"msExchMasterAccountSid"=$objectSid}
#enable targetaccount
$TargetAccount | Enable-ADAccount
#disable the source account
$SourceAccount | Disable-ADAccount
#move the migrated user into prod OU
$TargetAccount | Move-ADObject -TargetPath "ou=test,dc=contoso,dc=com"
Thanks

here is a demo of the concept i was trying to get across. [grin] it keeps the association of the objects in your CSV in the original object for as long as possible. the code has NOT been tested since i have no AD access.
what it does ...
fakes reading in a CSV file
when you are ready to use real data, replace the entire "region" with a call to Import-CSV.
iterates thru the list
builds a splat of the parameters for the AD calls
see Get-Help about_Splatting for more info on that wonderfully useful idea.
calls Get-AdUser with each to the Source/Target user data sets
stores the above
uses the stored account info to ...
== replace the .objectSid of the Target account
== enable the Target account
== disable the Source account
== Move the Target account to the desired OU
the hard coded OU could be set with a variable to make this a tad more flexible. however, this seems to be a one-off operation - so there is likely no benefit.
if you want to add logging, do so in the same loop.
there is no error handling, either. that likely should be added with a try/catch around each AD call & logging of both success and failure.
the code ...
#region >>> fake reading in a CSV file
# in real life, use Import-CSV
$UserList = #'
SourceUser, DestUser
ABravo#Old.com, ABravo#NewDomain.com
BCharlie#Old.com, BCharlie#NewDomain.com
CDelta#Old.com, CDelta#NewDomain.com
DEcho#Old.com, DEcho#NewDomain.com
EFoxtrot#Old.com, EFoxtrot#NewDomain.com
'# | ConvertFrom-Csv
#endregion >>> fake reading in a CSV file
ForEach ($UL_Item in $UserList)
{
Write-Host 'Processing ...'
Write-Host (' SourceUser {0}' -f $UL_Item.SourceUser)
Write-Host (' DestinationUser {0}' -f $UL_Item.DestUser)
Write-Host '__ Source Account __'
$GADU_Params_1 = [ordered]#{
Identity = $UL_Item.SourceUser.Split('#')[0]
Server = $UL_Item.SourceUser.Split('#')[1]
Properties = 'objectSid'
}
$SourceAccount = Get-ADUser #GADU_Params_1
Write-Host '__ Target Account __'
$GADU_Params_2 = [ordered]#{
Identity = $UL_Item.DestUser.Split('#')[0]
Server = $UL_Item.DestUser.Split('#')[1]
}
$TargetAccount = Get-ADUser #GADU_Params_2
Write-Host 'Making changes ...'
# all these piped objects are slower than making _direct_ calls
# however, i don't have any way to test the code, so i can't use what likely is faster
# something like >>>
# Set-AdUser -Identity $TargetAccount -Replace #{
# 'msExchMasterAccountSid' = $objectSid
# }
# note that i also replaced the unneeded _double_ quotes with the safer _single_ quotes
$TargetAccount |
Set-AdUser -Replace #{
'msExchMasterAccountSid' = $SourceAccount.objectSid
}
$TargetAccount |
Enable-AdAccount
$SourceAccount |
Disable-AdAccount
$TargetAccount |
Move-AdObject -TargetPath 'ou=test,dc=contoso,dc=com'
Write-Host '=' * 30
Write-Host ''
}
no output shown since i can't actually run this AD stuff. [grin]

$SourceUsers and $DestinationUsers contain only the last ones becasue youa re replacing the value on each foreach iteration.
if you want it to separate the properties try this:
$SourceUsers = $User | select SourceUser -ExpandProperty SourceUser
$DestinationUsers = $User | select DestinationUser -ExpandProperty DestinationUser
That will create a collection of only those strings. you wont be able to access those values by property anymore, meaning that is a simple String[] after the -ExpandProperty.

$SourceUsers = #()
$DestinationUsers = #()
$Results = ForEach ($User in $listofusers) {
Write-Host "Processing SourceUser $($User.SourceUser)"
Write-Host "Processing DestinationUser $($User.DestinationUser)"
#Assign the content to variables
$SourceUsers += $User.SourceUser
$DestinationUsers += $User.DestinationUser
}
$SourceUsers = #() and $DestinationUsers = #() creates two empty
arrays which we will use in the loop
+= is an assignment operator which enables us to assign more than
one value to a variable. According to the documentation: Increases
the value of a variable by the specified value, or appends the
specified value to the existing value.

Related

Powershell Editing Strings in Array

My array has a lot of properties but I'm only looking to edit one. The goal is to remove domains from the hostname but I haven't been able to get it working. This data is being returned from a REST API and there are thousands of assets that contain the same type of data (JSON content). The end goal is to compare assets pulled from the API and compare it to assets in a CSV file. The issue is that the domain may appear on one list and not the other so I'm trying to strip the domains off for comparison. I didn't want to iterate through both files and the comparison has to go from the CSV file to the API data hence the need to get rid of the domain altogether.
There are other properties in the array that I will need to pull from later. This is just an example of one of the arrays with a few properties:
$array = #{"description"="data"; "name"="host1.domain1.com"; "model"="data"; "ip"="10.0.0.1"; "make"="Microsoft"}
#{"description"="data"; "name"="host2.domain2.com"; "model"="data"; "ip"="10.0.0.2"; "make"="Different"}
#{"description"="data"; "name"="10.0.0.5"; "model"="data"; "ip"="10.0.0.5"; "make"="Different"}
The plan was to match the domain and then strip using the period.
$domainList = #(".domain1.com", ".domain2.com")
$domains = $domainList.ForEach{[Regex]::Escape($_)} -join '|'
$array = $array | ForEach-Object {
if($_.name -match $domains) {
$_.name = $_.name -replace $domains }
$_.name
}
You may do the following to output a new array of values without the domain names:
# starting array
$array = #("hosta.domain1.com", "hostb.domain2.com", "host3", "10.0.0.1")
# domains to remove
$domains = #('.domain1.com','.domain2.com')
# create regex expression with alternations: item1|item2|item3 etc.
# regex must escape literal . since dot has special meaning in regex
$regex = $domains.foreach{[regex]::Escape($_)} -join '|'
# replace domain strings and output everything else
$newArray = $array -replace $regex
Arrays use pointers so I needed to load the array and pipe through ForEach-Object and then set the object when logic was complete. Thanks for all of the help.
$domainList = #(".domain1.com", ".domain2.com")
$domains = $domainList.ForEach{[Regex]::Escape($_)} -join '|'
$array = $array | ForEach-Object {
if($_.name -match $domains) {
$_.name = $_.name -replace $domains }
$_.name
}

Outputting Array Into Excel

I've taken an issue with a fairly old script we use at my office to assign eFax numbers. Its owner is of course long gone. I've fixed the basic use issues with the script, but I'm trying to streamline it. The current issue I want to address is how it checks a number isn't in use.
I've deciphered that the current build has the phone number ranges listed in a text file like "236,4000,4199" and then it goes through that range and checks each number against every user profile in Active Directory, so its certainly slow. So what I'm looking at is a way to have the array of phone numbers (about 4k total) pulled and entered into a spreadsheet and then I would just use a separate script to do that check against AD to remove the ones in use. That way it just needs to reference a single document instead of a few thousand numbers against a few thousand users.
I don't have anything yet on putting it into Excel as I haven't fully understood the array to verify the phone number and I don't know how I'd output each number into Excel. Here's the original code related to the array to read the numbers:
ipmo act*
$FaxNUmbersINuse = #()
$AvailableFaxNumbers = #()
$AllFaxNumbers = #()
# - WFM Fax Numbers
$FaxNumberRange = Get-Content "\\CEWP9023\Share\FaxNumberRange.txt"
# - Get all Fax numbers
Write-Host "Generating fax numbers..."
foreach ($FaxNumber in $FaxNumberRange) {
$inparray = $FaxNumber.Split(',')
$v1 = $inparray[0]
$v2 = $inparray[1]
$v3 = $inparray[2]
$AllFaxNumbers += $v2..$v3 | foreach {"512-"+$v1+"-"+$_}
}
$FaxNumbersList = $null
$FaxNumbersList = #{}
$TMwithFaxs = Get-ADUser -Filter 'Fax -like "512-*"' -SearchBase "OU=REGIONS,DC=wfm,DC=pvt" -Properties * | select DisplayName, Fax
foreach ($TM in $TMwithFaxs) {
$FaxNumbersList.Add($TM.DisplayName, $TM.Fax)
}
foreach ($AllFaxNumber in $AllFaxNumbers) {
if ($FaxNumbersList.ContainsValue($AllFaxNumber)) {
$FaxNUmbersINuse += $FaxNumbersList
If you are making a new CSV file (and not modifying an existing one), consider Export-CSV.
I'm looking at is a way to have the array of phone numbers (about 4k total) pulled and entered into a spreadsheet
You can export the generated range or the Active Directory range using these lines. I've put them into the script below, and annotated it to try and explain how the numbers are generated.
$AllFaxNumbers | Out-File "C:\temp\AllFaxNumber.txt"
$TMwithFaxs | Export-Csv "C:\temp\ADFaxNumbers.csv" -NoType
The reason these are two different methods is because of the types of objects.
$AllFaxNumbers is an array. It's a simple list of fax numbers and has a single property - Length - that tells you how many fax numbers are in it.
TMwithFaxs is a bit more complex; it's a Microsoft.ActiveDirectory.Management.ADUser object*, with only the Displayname and Fax pulled out and all of the other AD information discarded.
Most likely this won't resolve everything for you - it's best to break your problem down into pieces and ask about a specific problem when you post a question.
ipmo act*
$FaxNUmbersINuse = #()
$AvailableFaxNumbers = #()
$AllFaxNumbers = #()
# - WFM Fax Numbers
$FaxNumberRange = Get-Content "\\CEWP9023\Share\FaxNumberRange.txt"
# - Get all Fax numbers
Write-Host "Generating fax numbers..."
#using 236,4000,4199 as an example
foreach ($FaxNumber in $FaxNumberRange) {
$inparray = $FaxNumber.Split(',') # split 236,4000,4199 into an array
$v1 = $inparray[0] # 236 is the first element
$v2 = $inparray[1] # 4000 is the second element
$v3 = $inparray[2] # 4199 is the third element
# generate the numbers "512-236-4000" to "512-236-4199"
# i.e. "512-236-4000", "512-236-4001", "512-236-4002" etc
$AllFaxNumbers += $v2..$v3 | foreach {"512-"+$v1+"-"+$_}
}
$AllFaxNumbers | Out-File "C:\temp\AllFaxNumber.txt"
$FaxNumbersList = $null
$FaxNumbersList = #{}
$TMwithFaxs = Get-ADUser -Filter 'Fax -like "512-*"' -SearchBase "OU=REGIONS,DC=wfm,DC=pvt" -Properties * | select DisplayName, Fax
$TMwithFaxs | Export-Csv "C:\temp\ADFaxNumbers.csv" -NoType
foreach ($TM in $TMwithFaxs) {
$FaxNumbersList.Add($TM.DisplayName, $TM.Fax)
}
foreach ($AllFaxNumber in $AllFaxNumbers) {
if ($FaxNumbersList.ContainsValue($AllFaxNumber)) {
$FaxNUmbersINuse += $FaxNumbersList
* Because you've selected a subset of all available properties, it may just be a generic PSObject - i don't have AD locally to test.
If I understand the question correctly, you have a text file from which you can generate a list of all possible fax numbers.
Next, you want to compare that to the numbers found in AD and using that, you want to create a new file containing all numbers that are available.
This approach is maybe a little different in that it creates a single CSV file for import in Excel with information about both the used and the available numbers.
The resulting CSV file will be like:
"UserName","FaxNumber","Available"
"Billy Joel","512-326-4000","No"
"","512-326-4001","Yes"
"Alice Cooper","512-326-4002","No"
The code for this:
Import-Module ActiveDirectory
$path = '\\CEWP9023\Share'
$adSearchBase = 'OU=REGIONS,DC=wfm,DC=pvt'
##########################################################
# Step 1: read the number ranges from the text file
##########################################################
# - WFM Fax Numbers. Format: AreaCode, RangeStart, RangeEnd
$faxNumberRange = Get-Content (Join-Path -Path $path -ChildPath 'FaxNumberRange.txt')
# - Get all Fax possible numbers
Write-Host "Generating all possible fax numbers..."
# use a HashSet object for faster lookup
$generatedNumbers = New-Object 'System.Collections.Generic.HashSet[String]'
foreach ($item in $faxNumberRange) {
$areaCode, [int]$rangeStart, [int]$rangeEnd = $item -split ','
# add the numbers unformatted for easier comparison later
$rangeStart..$rangeEnd | ForEach-Object {
[void]$generatedNumbers.Add(("512{0}{1}" -f $areaCode, $_ ))
}
}
##########################################################
# Step 2: find AD users with faxnumber
##########################################################
# create a list containing PSCustomObjects storing user DisplayName
# and the faxnumber as it is entered in AD
Write-Host "Retrieving all users with fax numbers..."
# create a Hasttable for the info gathered from AD
$userNumbers = #{}
Get-ADUser -Filter 'Fax -like "512-*"' -SearchBase $adSearchBase -Properties DisplayName, Fax |
ForEach-Object {
$fax = $_.Fax -replace '\D', '' # remove all non-numeric characters
if ($userNumbers.ContainsKey($fax)) {
# Hmmmm. This number is already in the list. Possibly two or more users are found with the same number
# Add this Nth user with a pipe symbol to the UserName property.
$userNumbers.$fax.UserName += (' | {0}' -f $_.DisplayName)
}
else {
$faxInfo = [PSCustomObject]#{
UserName = $_.DisplayName
FaxNumber = $_.Fax
Available = 'No'
}
# use the unformatted faxnumber as Key
$userNumbers.$fax = $faxInfo
}
}
##########################################################
# Step 3: create a final list containing all numbers
##########################################################
# Test each generated number against the (unformatted) AD faxnumbers
# and add them in a new All-Numbers list
Write-Host "Generating complete list of fax numbers and users..."
# use an arraylist object for better performance
$allNumbers = New-Object 'System.Collections.ArrayList'
# loop through all generated numbers
foreach ($fax in $generatedNumbers) {
if ($userNumbers.ContainsKey($fax)) {
# this is a number in use so add the info from AD
[void]$allNumbers.Add($userNumbers.$fax)
}
else {
# create a new entry for this unused number
$faxInfo = [PSCustomObject]#{
UserName = '' # no user DisplayName also means: number is available
FaxNumber = '{0}-{1}-{2}' -f $fax.Substring(0,3), $fax.Substring(3,3), $fax.Substring(6)
Available = 'Yes'
}
[void]$allNumbers.Add($faxInfo)
}
}
# you can free some memory here
$generatedNumbers.Clear()
$userNumbers.Clear()
# output the completed list as CSV file
$allNumbers.ToArray() | Export-Csv -Path (Join-Path -Path $path -ChildPath 'AllFaxNumbers.csv') -NoTypeInformation

Powershell-Azure WebApp IpRestrictions - WebApps Array

I have been struggling to come up with a working solution for days on this
What am I trying to achieve?
Foreach ($item in $webApps){
$WebAppConfig = (Get-AzureRmResource -ResourceType Microsoft.Web/sites/config -ResourceName $item -ResourceGroupName $resourceGroup -ApiVersion $APIVersion)
}
The issue is that "-resourceName" will not accept objects, but rather only a string
I am looking for a way to take the output of the following command, convert it to a string, so that it can satisfy –ResourceName, and loop through each item in the string
$webApps = (Get-AzureRmResourceGroup -Name $resourceGroup | Get-AzureRmWebApp).name
This returns a nice list of Azure WebApps that exist in a specified ResourceGroup, however they are in object form, which –ResourceName will not take
I have tried several ways to convert the output of $webApps to a string, add a comma to the end, then do a –split ',' but nothing seems to work for properly, where –ResourceName will accept it
Method 1:
[string]$webAppsArrays =#()
Foreach ($webApp in $webApps){
$webAp+',' -split ','
}
Method 2:
$
webApps | ForEach-Object {
$webApp = $_ + ","
Write-Host $webApp
}
Method 3:
$csvPath2 = 'C:\Users\Giann\Documents\_Git Repositorys\QueriedAppList2.csv'
$webApps = (Get-AzureRmResourceGroup -Name $resourceGroup | Get-AzureRmWebApp).name | out-file -FilePath $csvPath1 -Append
$csvFile2 = import-csv -Path $csvPath1 -Header Name
This ouputs a list in a CSV, however these are still objects, so I cannot pass each item into –ResourceName
I am going in circles trying to make the below a repeatable, looping script
The desired end result would be to use the below script, with an array of webApps, being queried from the provided resource group variable:
Any help would be greatly appreciated for how to use this script, but pull a dynamic list of WebApps from a specified Resource Group, keeping in mind the -ResourceName "String" restrictions in the $WebAppConfig variable
Here is the original script to create IP Restrictions for 1 Web App and 1 Resource Group, using properties from a CSV file:
#Create a Function to create IP Restrictions for 1 Web App and 1 Resource Group, using properties from the CSV file:
#Variables
$WebApp = ""
$resourceGroup =""
$subscription_Id = ''
#Login to Azure
Remove-AzureRmAccount -ErrorAction SilentlyContinue | Out-Null
Login-AzureRmAccount -EnvironmentName AzureUSGovernment -Subscription $subscription_Id
Function CreateIpRestriction {
Param (
[string] $name,
[string] $ipAddress,
[string] $subnetMask,
[string] $action,
[string] $priority
)
$APIVersion = ((Get-AzureRmResourceProvider -ProviderNamespace Microsoft.Web).ResourceTypes | Where-Object ResourceTypeName -eq sites).ApiVersions[0]
$WebAppConfig = (Get-AzureRmResource -ResourceType Microsoft.Web/sites/config -ResourceName $WebApp -ResourceGroupName $ResourceGroup -ApiVersion $APIVersion)
$ipRestriction = $WebAppConfig.Properties.ipSecurityRestrictions
$ipRestriction.name = $name
$ipRestriction.ipAddress = $ipAddress
$ipRestriction.subnetMask = $subnetMask
$ipRestriction.action = $action
$ipRestriction.priority = $priority
return $ipRestriction
}
#Set csv file path:
$csvPath5 = 'C:\Users\Giann\Documents\_Git Repositorys\ipRestrictions5.csv'
#import CSV Contents
$ipRestrictionArray = Import-Csv -Path $csvPath5
$ipRestrictions = #()
foreach($item in $ipRestrictionArray){
Write-Host "Adding ipRestriction properties for" $item.name
$newIpRestriction = CreateIpRestriction -name $item.name -ipAddress $item.ipAddress -subnetMask $item.subnetMask -action $item.action -priority $item.priority
$ipRestrictions += $newIpRestriction
}
#Set the new ipRestriction on the WebApp
Set-AzureRmResource -ResourceGroupName $resourceGroup -ResourceType Microsoft.Web/sites/config -ResourceName $WebApp/web -ApiVersion $APIVersion -PropertyObject $ipRestrictions
As continuation on the comments, I really need multiline, so here as an answer.
Note that I cannot test this myself
This page here shows that the Set-AzureRmResource -Properties parameter should be of type PSObject.
(instead of -Properties you may also use the alias -PropertyObject)
In your code, I don't think the function CreateIpRestriction returns a PSObject but tries to do too much.
Anyway, try like this:
Function CreateIpRestriction {
Param (
[string] $name,
[string] $ipAddress,
[string] $subnetMask,
[string] $action,
[string] $priority
)
# There are many ways to create a PSObject (or PSCustomObject if you like).
# Have a look at https://social.technet.microsoft.com/wiki/contents/articles/7804.powershell-creating-custom-objects.aspx for instance.
return New-Object -TypeName PSObject -Property #{
name = $name
ipAddress = $ipAddress
subnetMask = $subnetMask
action = $action
priority = $priority
}
}
#Set csv file path:
$csvPath5 = 'C:\Users\Giann\Documents\_Git Repositorys\ipRestrictions5.csv'
#import CSV Contents
$ipRestrictionArray = Import-Csv -Path $csvPath5
# create an new array of IP restrictions (PSObjects)
$newIpRestrictions = #()
foreach($item in $ipRestrictionArray){
Write-Host "Adding ipRestriction properties for" $item.name
$newIpRestrictions += (CreateIpRestriction -name $item.name -ipAddress $item.ipAddress -subnetMask $item.subnetMask -action $item.action -priority $item.priority )
}
# here we set the restrictions we collected in $newIpRestrictions in the $WebAppConfig.Properties.ipSecurityRestrictions array
$APIVersion = ((Get-AzureRmResourceProvider -ProviderNamespace Microsoft.Web).ResourceTypes | Where-Object ResourceTypeName -eq sites).ApiVersions[0]
$WebAppConfig = (Get-AzureRmResource -ResourceType Microsoft.Web/sites/config -ResourceName $WebApp -ResourceGroupName $ResourceGroup -ApiVersion $APIVersion)
$WebAppConfig.Properties.ipSecurityRestrictions = $newIpRestrictions
$WebAppConfig | Set-AzureRmResource -ApiVersion $APIVersion -Force | Out-Null
The code above will replace the ipSecurityRestrictions by a new set. You may want to consider first getting them and adding to the already existing list.
I found examples for Getting, Adding and Removing ipSecurityRestrictions here, but I can imagine there are more examples to be found.
Hope that helps.

Powershell Looping through eventlog

I am trying to gather data from eventlogs of logons, disconnect, logoff etc... this data will be stored in a csv format.
This is the script i am working which got from Microsoft Technet and i have modified to meet my requirement. Script is working as it should be but there is looping going on which i can't figure out how it should be stopped.
$ServersToQuery = Get-Content "C:\Users\metho.HOME\Desktop\computernames.txt"
$cred = "home\Administrator"
$StartTime = "September 19, 2018"
#$Yesterday = (Get-Date) - (New-TimeSpan -Days 1)
foreach ($Server in $ServersToQuery) {
$LogFilter = #{
LogName = 'Microsoft-Windows-TerminalServices-LocalSessionManager/Operational'
ID = 21, 23, 24, 25
StartTime = (Get-Date).AddDays(-1)
}
$AllEntries = Get-WinEvent -FilterHashtable $LogFilter -ComputerName $Server -Credential $cred
$AllEntries | Foreach {
$entry = [xml]$_.ToXml()
$Output += New-Object PSObject -Property #{
TimeCreated = $_.TimeCreated
User = $entry.Event.UserData.EventXML.User
IPAddress = $entry.Event.UserData.EventXML.Address
EventID = $entry.Event.System.EventID
ServerName = $Server
}
}
}
$FilteredOutput += $Output | Select TimeCreated, User, ServerName, IPAddress, #{Name='Action';Expression={
if ($_.EventID -eq '21'){"logon"}
if ($_.EventID -eq '22'){"Shell start"}
if ($_.EventID -eq '23'){"logoff"}
if ($_.EventID -eq '24'){"disconnected"}
if ($_.EventID -eq '25'){"reconnection"}
}
}
$Date = (Get-Date -Format s) -replace ":", "-"
$FilePath = "$env:USERPROFILE\Desktop\$Date`_RDP_Report.csv"
$FilteredOutput | Sort TimeCreated | Export-Csv $FilePath -NoTypeInformation
Write-host "Writing File: $FilePath" -ForegroundColor Cyan
Write-host "Done!" -ForegroundColor Cyan
#End
First time when i run the script, it runs fine and i get the csv output as it should be. When i run the script again than a new CSV is created (as it should be) but the same event log enteries are created twice and run it again than three enteries are created for the same event. This is very strange as a new csv is created each time and i dont not have -append switch for export-csv configured.
$FilteredOutput = #()
$Output = #()
I did try adding these two lines in above script as i read somewhere that it is needed if i am mixing multiple variables into a array (i do not understand this so applogies if i get this wrong).
Can someone please help me this, more importantly, I need to understand this as it is good to know for my future projects.
Thanks agian.
mEtho
It sounds like the$Output and $FilteredOutput variables aren't getting cleared when you run the script subsequent times (nothing in the current script looks to do that), so the results are just getting appended to these variables each time.
As you've already said, you could add these to the top of your script:
$FilteredOutput = #()
$Output = #()
This will initialise them as empty arrays at the beginning, which will ensure they start empty as well as make it possible for them to be appended to (which happens at the script via +=). Without doing this on the first run the script likely failed, so I assume you must have done this in your current session at some point for it to be working at all.

Create a String array from an object array in powershell

Im getting the names of these computers and putting them into an array. Now what i want to do is to convert them into a string array to be able to check which policy they are on using a Get-ADComputer for loop or using a foreach loop (Can you recommend which one to use)
$global:arrComputers = #()
$computerStrings = Get-ADComputer -Filter 'SamAccountName -like "*Name*"' | Select -Expand Name
foreach ($line in $computerStrings)
{
$a = $line.ToString()
$b = $a.split()
$temp = #{}
$temp = New-Object object
$temp | Add-Member -MemberType "noteproperty" -Name Name -Value $b[0]
$global:arrComputers += $temp
}
$global:arrComputers
This is the command i want to run to check the policy they are under
Get-ADComputer "Name" -Properties MemberOf | %{if ($_.MemberOf -like "*POLICY_NAME*") {Write-Host "ON"} else {Write-Host "NOT ON"}}
I have tested both blocks of code and they are working the only problem im having is turning that array into a string array. I also tried the ToString() To be able to loop through it with the Get-ADComputer "Name"
"memberOf" property in objects returned by "Get-ADComputer" returns a list of strings containing Distinguished Name of each group this computer is a member of.
Therefore, I assume when you say "This is the command i want to run to check the policy they are under", you are referring to a group membership that a group policy is targeting right?
Below code then will do it:
$computers = #();
Get-ADComputer -Filter * -Properties Name,MemberOf | %{if ($_.MemberOf -like "*computer_group_name*") { $computers += $_.Name } }
Explanation:
First line, define an array $computers
Second line, query AD for computer object properties Name,MemberOf
then, $_.MemberOf contains group name in string, add Name property(string) to array of strings you defined on line 1

Resources