Yesterday I asked this question. Now I would like to do almost the same exercise with a small change: if there is a blank character on a line (go line by line in the CSV) ask the user if the blank character should be removed or not; the difference is, ONLY the blank and not the whole line.
The code which works for my previous question is:
$yes = New-Object System.Management.Automation.Host.ChoiceDescription "&Yes", "Retain line."
$no = New-Object System.Management.Automation.Host.ChoiceDescription "&No", "Delete line."
$n = #()
$f = Get-Content .\test.csv
foreach ($item in $f) {
if($item -like "* *"){
$res = $host.ui.PromptForChoice("Title", "want to keep this line? `n $item", [System.Management.Automation.Host.ChoiceDescription[]]($yes, $no), 0)
switch ($res) {
0 {$n+=$item}
1 {}
}
} else {
$n+=$item
}
}
$n | Set-Content .\test.csv
What I think I should use is the Trim() function to achieve this.
So, I think I should modify in the if clause like below (aplogies for the silly syntax mistakes which I might do):
$yes = New-Object System.Management.Automation.Host.ChoiceDescription "&Yes", "Retain blank."
$no = New-Object System.Management.Automation.Host.ChoiceDescription "&No", "Delete blank."
$n = #()
$f = Get-Content .\test.csv
foreach ($item in $f) {
if ($item -like "* *") {
$res = $host.ui.PromptForChoice("Title", "want to keep the blank on this line? `n $item", [System.Management.Automation.Host.ChoiceDescription[]]($yes, $no), 0)
switch ($res) {
0 {$n+=$item.Trim()}
1 {}
}
} else {
$n+=$item.Trim()
}
}
$n | Set-Content .\test.csv
This runs, but still deteles the line, so it shouldn't matter if I trimmed it or not first, I need to fix it so it will be kept or trimmed but not discarded .
EDIT:
Adjusting the switch ($res) like this doesn't work:
switch ($res) {
0 {$n+=$item.Trim()}
1 {$n+=$item}
}
} else {
$n+=$item.Trim()
}
Trim() without parameter removes all whitespace (not just spaces) from beginning and end of a string. You can't use it for removing spaces anywhere else in a string. Instead use the -replace operator:
$_ -replace ' '
Note that this time you need to output the unmodified string not only if it doesn't contain a space, but also if the user chooses to keep the existing space(s).
Related
I have a string needs to be changed in a file between two values. What I want to do is if I found value A then change to value B, if I found value B then change to value A. there will be a message box popup saying that value has been changed to [xxxxx] then background picture will be also changed accordingly.
$path = c:\work\test.xml
$A = AAAAA
$B = BBBBB
$settings = get-content $path
$settings | % { $_.replace($A, $B) } | set-content $path
I could not figured out how to use IF A then replace with B or IF B then replace A. Also, the code above will delete rest of contents in the file and only save the part that I modified back to the file.
Assuming that $A and $B contain just simple strings rather than regular expressions you could use a switch statement with wildcard matches:
$path = 'c:\work\test.xml'
$A = 'AAAAA'
$B = 'BBBBB'
(Get-Content $path) | % {
switch -wildcard ($_) {
"*$A*" { $_ -replace [regex]::Escape($A), $B }
"*$B*" { $_ -replace [regex]::Escape($B), $A }
default { $_ }
}
} | Set-Content $path
The [regex]::Escape() makes sure that characters having a special meaing in regular expressions are escaped, so the values are replaced as literal strings.
If you're aiming for something a little more advanced, you could use a regular expression replacement with a callback function:
$path = 'c:\work\test.xml'
$A = 'AAAAA'
$B = 'BBBBB'
$rep = #{
$A = $B
$B = $A
}
$callback = { $rep[$args[0].Groups[1].Value] }
$re = [regex]("({0}|{1})" -f [regex]::Escape($A), [regex]::Escape($B))
(Get-Content $path) | % {
$re.Replace($_, $callback)
} | Set-Content $path
This isn't tested extensively, but I think it should work:
path = c:\work\test.xml
$A = 'AAAAA'
$B = 'BBBBB'
[regex]$regex = "$A|$B"
$text =
Get-Content $path |
foreach {
$regex.Replace($text,{if ($args[0].value -eq $A){$B} else {$A}})
}
$text | Set-Content $path
Hard to be sure without knowing exactly what the data looks like.
I would like to be able to find all blanks from a CSV file and if a blank character is found on a line then should appear on the screen and I should be asked if I want to keep the entire line which contains that white space or remove it.
Let's say the directory is C:\Cr\Powershell\test. In there there is one CSV file abc.csv.
Tried doing it like this but in PowerShell ISE the $_.PSObject.Properties isn't recognized.
$csv = Import-Csv C:\Cr\Powershell\test\*.csv | Foreach-Object {
$_.PSObject.Properties | Foreach-Object {$_.Value = $_.Value.Trim()}
}
I apologize for not includding more code and what I tried more so far but they were silly attempts since I just begun.
This looks helpful but I don't know exactly how to adapt it for my problem.
Ok man here you go:
$yes = New-Object System.Management.Automation.Host.ChoiceDescription "&Yes", "Retain line."
$no = New-Object System.Management.Automation.Host.ChoiceDescription "&No", "Delete line."
$n = #()
$f = Get-Content .\test.csv
foreach($item in $f) {
if($item -like "* *"){
$res = $host.ui.PromptForChoice("Title", "want to keep this line? `n $item", [System.Management.Automation.Host.ChoiceDescription[]]($yes, $no), 0)
switch ($res)
{
0 {$n+=$item}
1 {}
}
} else {
$n+=$item
}
}
$n | Set-Content .\test.csv
if you have questions please post in the comments and i will explain
Get-Content is probably a better approach than Import-Csv, because that'll allow you to check an entire line for spaces instead of having to check each individual field. For fully automated processing you'd just use a Where-Object filter to remove non-matching lines from the output:
Get-Content 'C:\CrPowershell\test\input.csv' |
Where-Object { $_ -notlike '* *' } |
Set-Content 'C:\CrPowershell\test\output.csv'
However, since you want to prompt for each individual line that contains spaces you need a ForEach-Object (or a similiar construct) and a nested conditional, like this:
Get-Content 'C:\CrPowershell\test\input.csv' | ForEach-Object {
if ($_ -notlike '* *') { $_ }
} | Set-Content 'C:\CrPowershell\test\output.csv'
The simplest way to prompt a user for input is Read-Host:
$answer = Read-Host -Prompt 'Message'
if ($answer -eq 'y') {
# do one thing
} else {
# do another
}
In your particular case you'd probably do something like this for any matching line:
$anwser = Read-Host "$_`nKeep the line? [y/n] "
if ($answer -ne 'n') { $_ }
The above checks if the answer is not n to make removal of the line a conscious decision.
Other ways to prompt for user input are choice.exe (which has the additional advantage of allowing a timeout and a default answer):
choice.exe /c YN /d N /t 10 /m "$_`nKeep the line"
if ($LastExitCode -ne 2) { $_ }
or the host UI:
$title = $_
$message = 'Keep the line?'
$yes = New-Object Management.Automation.Host.ChoiceDescription '&Yes'
$no = New-Object Management.Automation.Host.ChoiceDescription '&No'
$options = [Management.Automation.Host.ChoiceDescription[]]($yes, $no)
$answer = $Host.UI.PromptForChoice($title, $message, $options, 1)
if ($answer -ne 1) { $_ }
I'm leaving it as an exercise for you to integrate whichever prompting routine you chose with the rest of the code.
Given this basic function:
Function TestFunction {
Param ( [int]$Par1, [string]$Par2, [string]$Par3 )
If ($Par1 -ne $Null) { Write-Output "Par1 = $Par1" }
If ($Par2 -ne $Null -or $Par2 -ne '') { Write-Output "Par2 = $Par2" }
If ($Par3 -ne $Null) { Write-Output "Par3 = $Par3" }
}
TestFunction -Par1 1 -Par3 'par3'
...the output is:
Par1 = 1
Par2 =
Par3 = par3
Even though I didn't pass anything into the $Par2 variable, it still isn't Null or empty. What happened, and how can I rewrite the statement so that the second If-statement evaluates as False and the script-block does not get executed?
(I added the -or $Par2 -ne '' just to test, it behaves the same with and without it.)
You have a logic error in your program: $Par2 will always be not equal to $null or not equal to ''.
To fix the logic, you should use -and instead of -or here:
If ($Par2 -ne $Null -and $Par2 -ne '') { Write-Output "Par2 = $Par2" }
However, because you casted the $Par2 argument to a string in the function's argument list:
Param ( [int]$Par1, [string]$Par2, [string]$Par3 )
^^^^^^^^
the check for $Par2 -ne $Null is unnecessary since $Par2 will always be of type string (if you do not give it a value, it will be assigned to ''). So, you should actually write:
If ($Par2 -ne '') { Write-Output "Par2 = $Par2" }
Or, because '' evaluates to false, you might just do:
If ($Par2) { Write-Output "Par2 = $Par2" }
You can check that (check if $variablename has $null as value):
if (!$variablename) { Write-Host "variable is null" }
And if you wanna check if $variablename has any value except $null:
if ($variablename) { Write-Host "variable is NOT null" }
I've got a function which works fine.
It pulls the first character of the firstname and the whole lastname from a text box in a PowerShell GUI and then it creates a sAMAccountName from both.
Now I need only the first 8 characters from the generated sAMAccountName.
Here is the function
Function Set-sAMAccountName {
Param([Switch]$Csv=$false)
if(!$Csv)
{
$GivenName = $txtFirstName.text
$Surname = $txtLastName.text
}
else{}
Switch($XML.Options.Settings.sAMAccountName.Style | Where{$_.Enabled -eq $True} | Select -ExpandProperty Format)
{
"FirstName.LastName" {"{0}.{1}" -f $GivenName,$Surname}
"FirstInitialLastName" {"{0}{1}" -f ($GivenName)[0],$Surname}
"LastNameFirstInitial" {"{0}{1}" -f $Surname,($GivenName)[0]}
Default {"{0}.{1}" -f ($GivenName)[0],$Surname}
}
}
Any ideas?
Thx a lot in advance
Substring works like that:
you pass the index of where you want to start
you pass the index of where you want to end the reading of the substring (if your not passing anything it will go until the end of the string's length)
so in your case it will be start reading at index 0 end reading at index 8:
$str = "a simple string"
$newString = $str.Substring(0,8)
I really recommend to read about string manipulation here
Okay I got it now!
I've added the -and condition to check the length of the sAMAccountName and said -lt 8 and it's working now. The sAMAccountName is now 8 characters long.
This was the code before:
$txtName_TextChanged={
Write-Verbose "Creating required account fields"
if ($XML.Options.Settings.DisplayName.Generate -eq $True) {$txtDN.Text = Set-DisplayName}
if ($XML.Options.Settings.sAMAccountName.Generate -eq $True) {$txtsAM.Text = (Set-sAMAccountName)}
if ($XML.Options.Settings.UPN.Generate -eq $True) {$txtUPN.Text = Set-UPN}
}
And after the change:
$txtName_TextChanged={
Write-Verbose "Creating required account fields"
if ($XML.Options.Settings.DisplayName.Generate -eq $True) {$txtDN.Text = Set-DisplayName}
if ($XML.Options.Settings.sAMAccountName.Generate -eq $True -and $txtsAM.Text.Length -lt 8) {$txtsAM.Text = (Set-sAMAccountName)}
if ($XML.Options.Settings.UPN.Generate -eq $True) {$txtUPN.Text = Set-UPN}
}
Error I'm getting is the following
Missing closing '}' in statement block.
I'm using this to automate adding user to a .dat file which has hundreds of user's for one of our systems. I was task with taking this part over and well I don't like to do anything manually. So I wrote a script to do 95% of it for me and it removes user's just fine. But this function I'm trying here adds the user in 2 different specific places to keep it nice and net. I'm still learning powershell so any direction would be great and you wont hurt my feelings I'm no pro nor novice here.
Function Add{
$username = Read-Host "User to add to REP01-02 Printing"
$LOCreportADD1 = "\\rep01\E$\orant\Report60\Server\cgicmd.dat"
$LOCreportADD2 = "\\rep02\e$\orant\Report60\Server\cgicmd.dat"
$Username1 = $username+": "
$prd = "prd: "
$userid = "userid="
$henation = "/henation#rmsprd %*"
$Text1 = get-content $LOCreportADD1
$Text2 = get-content $LOCreportADD2
$NewText1 = #()
foreach ($Line in $Text1) {
if ($Line -eq "Insert new user1") {
$Line = $Line.Replace("Insert new user1 \", "Insert new user1 \")
$NewText1 += $Line
$NewText1 += $username1+$userid+$username+$henation
}
Elseif ($Line -eq "New User2") {
$Line = $Line.Replace("New User2 \", "New User2 \")
$NewText12 += $Line
$NewText12 += $username+$prd+$userid+$username+$henation
}
$NewText1 | Set-Content $LOCreportADD1
}
The error says it all. You are missing a } at the end to close the function.
Tips is to put your script in an editor (Like Notepad++) that can handle {} matching and it's easy to see if you miss a {/}.
The error says it all. You are missing a '}' at the end to close the foreach block..
Function Add{
$username = Read-Host "User to add to REP01-02 Printing"
$LOCreportADD1 = "\\rep01\E$\orant\Report60\Server\cgicmd.dat"
$LOCreportADD2 = "\\rep02\e$\orant\Report60\Server\cgicmd.dat"
$Username1 = $username+": "
$prd = "prd: "
$userid = "userid="
$henation = "/henation#rmsprd %*"
$Text1 = get-content $LOCreportADD1
$Text2 = get-content $LOCreportADD2
$NewText1 = #()
foreach ($Line in $Text1) {
if ($Line -eq "Insert new user1") {
$Line = $Line.Replace("Insert new user1 \", "Insert new user1 \")
$NewText1 += $Line
$NewText1 += $username1+$userid+$username+$henation
}
Elseif ($Line -eq "New User2") {
$Line = $Line.Replace("New User2 \", "New User2 \")
$NewText12 += $Line
$NewText12 += $username+$prd+$userid+$username+$henation
} # <---- This is your missing brace, to close out the Else condition
}
$NewText1 | Set-Content $LOCreportADD1
}
In the Powershell ISE you can highlight a '}'. It will then highlight the bracket it forms a block of code with. Highlight it, then right click it. Makes it easier to find your problem.