I've checked code and examples from identical questions on this site, but I'm baffled, because I'm utilizing nearly the exact same code from Get-ADUser with display name as a value and it just pulls empty results for me. I don't know how to continue a conversation on an existing question, so I figured I had to make my own.
Here is what I have:
import-module activedirectory
$csv = Get-Content users.csv
foreach ($user in $csv) {
$user = $user.trim()
write-host $user #A line for testing to show me what name is being analyzed
$samName = Get-ADUser -Filter{displayName -like "$user*"} | select samaccountname
write-host $samName
}
cmd /c pause | out-null
The output I get is:
John Doe
Jane Doe
Billy Ray
But if I change
$samName = Get-ADUser -Filter{displayName -like "$user*"} | select samaccountname
to:
$samName = Get-ADUser -Filter{displayName -like "John Doe*"} | select samaccountname
It will correctly return John Doe's samaccountname.
I need to read a file where the content is like below :
Computer Location = afp.local/EANG
Description = RED_TXT
Device Name = EANG04W
Domain Name = afp.local
Full Name = Admintech
Hardware Monitoring Type = ASIC2
Last Blocked Application Scan Date = 1420558125
Last Custom Definition Scan Date = 1348087114
Last Hardware Scan Date = 1420533869
Last Policy Sync Date = 1420533623
Last Software Scan Date = 1420533924
Last Update Scan Date = 1420558125
Last Vulnerability Scan Date = 1420558125
LDAP Location = **CN=EANG04W**,OU=EANG,DC=afp,DC=local
Login Name = ADMINTECH
Main Board OEM Name = Dell Inc.
Number of Files = 384091
Primary Owner = **CN= LOUHICHI anoir**,OU=EANG,DC=afp,DC=localenter code here
I need to replace CN=$value by CN=Compagny where $value is what is retrived after CN= and before ,.
Ok, so you really should have updated your question an not posted the code in a comment, because it's really hard to read. Here's what I think you intended:
$file = 'D:\sources\scripts\2.txt'
$content = Get-Content $file | foreach ($line in $content) {
if ($line.Contains('CN=')) {
$variable = $line.Split(',').Split('=')[2]
$variable1 = $variable -replace $variable, "Compagny"
} Set-Content -path $file
}
That deffinately has some syntax errors. The first line is great, you define the path. Then things go wrong... Your call to Get-Content is fine, that will get the contents of the file, and send them down the pipe.
You pipe that directly into a ForEach loop, but it's the wrong kind. What you really want there is a ForEach-Object loop (which can be confusing, because it can be shortened to just ForEach when used in a pipeline like this). The ForEach-Object loop does not declare an internal variable (such as ($line in $content)) and instead the scriptblock uses the automatic variable $_. So your loop needs to become something like:
Get-Content $file | ForEach { <do stuff> } | Set-Content
Next let's look inside that loop. You use an If statement to see if the line contains "CN=", understandable, and functional. If it does you then split the line on commas, and then again on equals, selecting the second record. Hm, you create an array of strings anytime you split one, and you have split a string twice, but only specify which record of the array you want to work with for the second split. That could be a problem. Anyway, you assign that substring to $variable, and proceed to replace that whole thing with "company" and store that output to $variable1. So there's a couple issues here. Once you split the string on the commas you have the following array of strings:
"LDAP Location = **CN=EANG04W**"
"OU=EANG"
"DC=afp"
"DC=local"
That's an array with 4 string objects. So then you try to split at least one of those (because you don't specify which one) on the equals sign. You now have an array with 4 array objects, where each of those has 2 string objects:
("LDAP Location", "**CN", "EANG04W**")
("OU", "EANG")
("DC","afp")
("DC","local")
You do specify the third record at this point (arrays in PowerShell start at record 0, so [2] specifies the third record). But you didn't specify which record in the first array so it's just going to throw errors. Let's say that you actually selected what you really wanted though, and I'm guessing that would be "EANG04W". (by the way, that would be $_.Split(",")[0].Split("=")[1]). You then assign that to $Variable, and proceed to replace all of it with "Company", so after PowerShell expands the variable it would look like this:
$variable1 = "EANG04W" -replace "EANG04W", "company"
Ok, you just successfully assigned "company" to a variable. And your If statement ends there. You never output anything from inside your If statement, so Set-Content has nothing to set. Also, it would set that nothing for each and every line that is piped to the ForEach statement, re-writing the file each time, but fortunately for you the script didn't work so it didn't erase your file. Plus, since you were trying to pipe to Set-Content, there was no output at the end of the pipeline, you have assigned absolutely nothing to $content.
So let's try and fix it, shall we? First line? Works great! No change. Now, we aren't saving anything in a variable, we just want to update a file's content, so there's no need to have $Content = there. We'll just move on then, shall we? We pipe the Get-Content into a ForEach loop, just like you tried to do. Once inside the ForEach loop, we're going to do things a bit differently though. The -replace method performs a RegEx match. We can use that to our advantage here. We will replace the text you are interested in for each line, and if it's not found, no replacement will be made, and pass each line on down the pipeline. That will look something like this for the inside of the ForEach:
$_ -replace "(<=CN\=).*?(?=,)", "Company"
The breakdown of that RegEx match can be seen here: https://regex101.com/r/gH6hP2/1
But, let's just say that it looks for text that has 'CN=' immediately before it, and goes up to the first comma following it. In your example, that includes the two trailing asterisks, but it doesn't touch the leading ones. Is that what you intended? That would make the last line of your example file:
Primary Owner = **CN=Company,OU=EANG,DC=afp,DC=localenter code here
Well, if that is as intended, then we have a winner. Now we close out the ForEach loop, and pipe the output to Set-Content and we're all set! Personally, I would highly suggest outputting to a new file, in case you need to reference the original file for some reason later, so that's what I'm going to do.
$file = 'D:\sources\scripts\2.txt'
$newfile = Join-Path (split-path $file) -ChildPath ('Updated-'+(split-path $file -Leaf))
Get-Content $file | ForEach{$_ -replace "(?<=CN\=).*?(?=,)", "Company"} | Set-Content $newfile
Ok, that's it. That code will produce D:\sources\scripts\Updated-2.txt with the following content:
Computer Location = afp.local/EANG
Description = RED_TXT
Device Name = EANG04W
Domain Name = afp.local
Full Name = Admintech
Hardware Monitoring Type = ASIC2
Last Blocked Application Scan Date = 1420558125
Last Custom Definition Scan Date = 1348087114
Last Hardware Scan Date = 1420533869
Last Policy Sync Date = 1420533623
Last Software Scan Date = 1420533924
Last Update Scan Date = 1420558125
Last Vulnerability Scan Date = 1420558125
LDAP Location = **CN=Company,OU=EANG,DC=afp,DC=local
Login Name = ADMINTECH
Main Board OEM Name = Dell Inc.
Number of Files = 384091
Primary Owner = **CN=Company,OU=EANG,DC=afp,DC=localenter code here
#GET TEXT FILE WITH LIST OF "SAMACCOUNTNAME" TO LIST VARIABLE
$list = Get-Content C:\PSSCripts\listofusers.txt
#PULL INFORMATION FROM ACTIVE DIRECTORY TO USERRESULTS VARIABLE
$UserResults = Get-AdUser -filter * -searchbase "OU=THISOU,DC=THISDOMAIN,DC=int" -Properties displayname
#DETERMINE IF USER IS IN THE TXT LIST
foreach ($user in $UserResults)
{
if ($user.SamAccountName -in $list.SamAccountName)
{
#ECHO THEIR NAME TO VERIFY
write-host $user.displayName
}
}
#VERIFY USER TO BE OFFBOARDED VIA Y/N PROMPT - VISUALLY INSPECT LIST
$choice = ""
while ($choice -notmatch "[y|n]"){
$choice = read-host "The following user profiles have been loaded for offboarding. Do you want to continue? Please Verify the users before continuing. (Y/N)"
}
if ($choice -eq "y"){
# LOOP THROUGH USERS AND APPLY CHANGES
foreach ($user in $UserResults)
{
#DETERMINE IF USER IS IN TXT FILE
if ($user.SamAccountName -in $list.SamAccountName)
{
# DISABLE ACCOUNT
Disable-ADAccount -Identity $user
# CHANGE DISPLAYNAME AND DESCRIPTION TO DISPLAY TERMINATED - $USER
$newname = "Terminated - " + $user.displayName
Get-ADUser -Identity $user | Set-ADObject -Description $newname -DisplayName $newname
# CHANGE USER PASSWORD TO "Password1"
$password = "Password1" | ConvertTo-SecureString -AsPlainText -Force
Set-ADAccountPassword -NewPassword $password -Identity $user -Reset
# MOVE USER TO DIFFERENT LOCATION, Disabled Users organizational unit
Move-ADObject -Identity $user -TargetPath "OU=DisabledUsers,DC=THATDOMAIN,DC=int" -Confirm:$false
}
}
}
else {write-host "Script aborted!"}
Getting the following error:
*You must provide a value expression on the right-hand side of the '-' operator. At :11 char:29
if ($user.SamAccountName - <<<< in $list.SamAccountName)
Category Info : ParserError (:) [], ParseException
FullyQualifiedErrorID : ExpectedValueExpression
I have a list of users in a text file with the header SAMACCOUNTNAME. These users are being checked against the list of users in a particular OU. Powershell will echo the list of users in my text list to me (after having checked it against all the users in that OU in AD - to verify nothing is being offboarded / changed in error), prompt to verify (y|n) before moving forward and executing a script I wrote with the help of some redditors from /r/powershell earlier.
I'm not understanding why I'm getting this error, is
-in $list.SamAccountName
Not correct?
Thanks for the help, stackoverflow! First time posting, looking forward to getting better with Powershell and giving back to the community.
You should use "-eq" or "-contains" (I am not sure what is a scalar value and what is an array in your program).
I have a requirement to export Windows Event logs to CSV from our production environment periodically.
I have a simple XML Config file containing a list of machines I need the events from, and a list of Event Ids that I need to retrieve.
From here I'm looping through each machine name in turn, and then each event Id to retrieve the logs and then export to CSV. I'd like one CSV per machine per execution.
Once I've worked out all my variables the PS Command is quite simple to retrieve the log for one Event Id
foreach ($machine in $config.Configuration.Machines.Machine)
{
$csvname=$outputlocation + $machine.Value + "_" + $datestring + ".csv"
foreach ($eventid in $config.Configuration.EventIds.EventId)
{
Get-WinEvent -ComputerName $machine.Value -ErrorAction SilentlyContinue -FilterHashTable #{Logname='Security';ID=$eventid.Value} | where {$_.TimeCreated -gt $lastexecutiondate} | export-csv -NoClobber -append $csvname
}
}
Execpt I'm unable to append to a CSV each time, PS 2.0 apparently does not support this. I've tried extracting all Event Ids at once but this seems to be a bit long winded and may now allow use of a config file, but I'm fairly new to PowerShell so I haven't had much luck.
I also need to specify multiple LogNames (System, Security and Application), and would prefer to run one statement as opposed to the same statement 3 times and appe but I'm unsure of how to do this.
Unfortunately at this point Google has me running in circles.
The following is something I culled together to allow me to export the prior 24 hours of events for select event logs - I'm going to create a scheduled task out of it so it pulls a daily.
Hope this helps someone else...
$eventLogNames = "Application", "Security", "System", "Windows PowerShell"
$startDate = Get-Date
$startDate = $startDate.addDays(-1).addMinutes(-15)
function GetMilliseconds($date)
{
$ts = New-TimeSpan -Start $date -End (Get-Date)
[math]::Round($ts.TotalMilliseconds)
}
$serverName = get-content env:computername
$serverIP = gwmi Win32_NetworkAdapterConfiguration |
Where { $_.IPAddress } | # filter the objects where an address actually exists
Select -Expand IPAddress | # retrieve only the property *value*
Where { $_ -notlike '*:*' }
$fileNameDate = Get-Date -format yyyyMMddhhmm
$endDate = Get-Date
$startTime = GetMilliseconds($startDate)
$endTime = GetMilliseconds($endDate)
foreach ($eventLogName in $eventLogNames)
{
Write-Host "Processing Log: " $eventLogName
<# - Remove comment to create csv version of log files
$csvFile = $fileNameDate + "_" + $serverIP +"_" + $eventLogName + ".csv"
Write-Host "Creating CSV Log: " $csvFile
Get-EventLog -LogName $eventLogName -ComputerName $serverName -After $startDate -ErrorAction SilentlyContinue | Sort MachineName, TimeWritten | Select MachineName, Source, TimeWritten, EventID, EntryType, Message | Export-CSV $csvFile #ConvertTo-CSV #Format-Table -Wrap -Property Source, TimeWritten, EventID, EntryType, Message -Autosize -NoTypeInformation
#>
$evtxFile = $fileNameDate + "_" + $serverIP + "_" + $eventLogName + ".evtx"
Write-Host "Creating EVTX Log: " $evtxFile
wevtutil epl $eventLogName $evtxFile /q:"*[System[TimeCreated[timediff(#SystemTime) >= $endTime] and TimeCreated[timediff(#SystemTime) <= $startTime]]]"
}
Why do I get Failed to export log Security. The specified query is invalid. I get this for each type of event log (system, application etc). This happens only to evtx export. I get the csv file tho`....
I want to be able to have multiple forms of the same parameter like so:
param(
[string]$p or $path = "C:\",
[string]$f or $filter = "*.txt",
[switch]$o or $overwrite
)
but I'm not sure how to do this. Most times, you would only be able to choose one (e.g. only $p or only $path). Is it possible to use multiple names for the same variable/parameter?
Like this:
param(
[Alias('p')]
[string]$path = "C:\",
[Alias('f')]
[string]$filter = "*.txt",
[Alias('o')]
[switch]$overwrite
)
Note you can have multiple aliases too: [Alias('p','thepath')]
PowerShell partial parameter name matching may be what your looking for.
# test.ps1
param($path)
write-host $path
Calling .\test.ps1 with either .\test.ps1 -path "c:\windows" or .\test.ps1 -p "c:\windows" will both match, and populate, the $path parameter.