Join fields in excel using powershell - csv

(1..$numrows) | ForEach-Object {
$sheet.Cells.Item($_,1) = -join $sheet.Cells.Item($numrows,1) + '-1234';
}
I am trying to join the -1234 in a row of a csv file
My result is System.__ComObject-1234
Could you please advise about the error message?

1 - You cannot start an expression with a switch, -join is not a command. Example use : $myJoinedArray = $array -join ";"
2 - You don't need -join, + is enough to concatenate strings.
3 - I think you want $sheet.Cells.Item($numrows,1).Value :
(1..$numrows) | ForEach-Object {
$sheet.Cells.Item($_,1) = $sheet.Cells.Item($numrows,1).Value + '-1234';
}

Related

How to use ADODB in PowerShell

I thought I'd post these code snippets for others who may find themselves trying to make ADODB calls from a PowerShell script. I inherited this convoluted mess, and had to make some changes to it.
We're using PlanetPress as part of a Docuware Document Imaging system. A PP workflow called a vbscript which in turn launched a PowerShell script. The PowerShell did the work to make two database queries. One was an update, and the other was a select. I'm not that great with PowerShell, and there may be a cmdlet out there to simplify this. But the code was creating ADODB.Connection, ADODB.Command, and ADODB.Resultset objects directly. The problem is there are no good resources for the syntax required to use these objects. Hopefully these code snippets will help some poor soul in a similar situation.
Using ADODB.Command:
$oConnection = New-Object -comobject "ADODB.Connection"
# Use correct ODBC driver
if ([Environment]::Is64BitProcess) {
$oConnection.Open("DSN=DW64")
} else {
$oConnection.Open("DSN=DW")
}
if ($oConnection.State -eq $adStateClosed) {
Write-Output "Connection not established"
Write-Output $oConnection
}
$UpdQuery = "Update dwdata.Purchasing `
set Status='Processing' `
WHERE DOCUMENT_TYPE = 'Check' `
AND STATUS in ('Approved')"
$ra=-1
$oCommand = New-Object -comobject "ADODB.Command"
$oCommand.ActiveConnection = $oConnection
$oCommand.CommandText = $UpdQuery
$oCommand.CommandType = $adCmdText
$rs=$oCommand.Execute([ref]$ra)
Write-Output ("Count of Row[s] updated: " + $ra)
Using ADODB.Resultset:
$oRS = New-Object -comobject "ADODB.Recordset"
$query = "SELECT DWDOCID, DOCUMENT_DATE, CHECK_NUMBER, PAYEE_NAME, CHECK_AMOUNT, STATUS `
FROM dwdata.Purchasing `
WHERE DOCUMENT_TYPE = 'Check' `
AND STATUS = 'Processing' `
ORDER BY CHECK_NUMBER;"
# $oConnection object created in ADODB.Command snippet above
$oConnection.CursorLocation = $adUseClient
$oRS.Open($query, $oConnection, $adOpenStatic, $adLockOptimistic)
$reccount = "Number of queried records: " + $oRS.RecordCount
write-output $reccount
If (-not ($oRS.EOF)) {
# Move to the first record returned, and loop
$oRS.MoveFirst()
$reccount = "Number of loop records: " + $oRS.RecordCount
write-output $reccount
do {
$outString = '"' + $oRS.Fields.Item("DOCUMENT_DATE").Value.ToString("MM/dd/yyyy") + '"' + ','
$outString += '"' + $oRS.Fields.Item("CHECK_NUMBER").Value + '"' + ','
$outString += '"' + $oRS.Fields.Item("PAYEE_NAME").Value + '"' + ','
$outString += '"' + $oRS.Fields.Item("CHECK_AMOUNT").Value + '"' + ','
$outString | Out-File $bankfile -Append -Encoding ASCII
$oRS.MoveNext()
} until
($oRS.EOF -eq $True)
} Else{
Write-Output "No records returned from database query."
}
$oRS.Close()
$oConnection.Close()
Some of this code is ugly (using do instead of while), but the idea is to help you get the right syntax for $oCommand.Execute and how to get a record count from the Recordset. $oRS.MoveFirst() needs to be called before the record count is available.
ss64.com and other resources usually give vbscript snippets. In vbscript variables are not preceeded with a $, and when or if you need to use parenthesis is unclear. This code does run and work.

Generate a CSV File

I am creating a powershell script, and one of the features is multi-user creation from a CSV.
I want it so after the script runs it clears the CSV file, then generates another with the correct headers.
Relevant Code
Script Beginning
[string]$csvpath = "multiusers.csv"
$csv = Import-Csv -Path "multiusers.csv"
Script End
Clear-Content $csvpath
Write-Output "User,First Name,Surname,Job Title,Department,Ticket Number,Managers First Name,Managers Surname" `n`n|FT -AutoSize >>multiusers.csv
In my mind, this should work, however all this does is create one large header.
You are using one long string as one column, seperate it to multiple strings first then Remove the | FT -AutoSize[...] Part, create a custom object row and use Export-CSV
Also, some of your columns contains spaces, you need to add quotes between them
Try this instead:
"" | Select User,"First Name",Surname,"Job Title",Department,"Ticket Number","Managers First Name","Managers Surname" | Export-csv multiusers.csv -NoTypeInformation
Another way using your string with split, like this:
$Columns = "User,First Name,Surname,Job Title,Department,Ticket Number,Managers First Name,Managers Surname" -split ","
"" | Select $Columns | Export-csv c:\multiusers.csv -NoTypeInformation
Or using Out-File if you don't want empty commas line.
$Columns = "User,First Name,Surname,Job Title,Department,Ticket Number,Managers First Name,Managers Surname" -split ","
(($Columns | % {'"{0}"' -f $_} ) -join ',') + "`n`n" | Out-File C:\multiusers.csv

Loop through a CSV file and verify column count for each row

I'm new to PowerShell and have been trying to loop through a CSV file and return column count of each row. Compare that column count to the first row and have something happen it its not equal. In this case replace comma with nothing. Then create a new file with the changes.
$csvColumnCount = (import-csv "a CSV file" | get-member -type NoteProperty).count
$CurrentFile = Get-Content "a CSV file" |
ForEach-Object { $CurrentLineCount = import-csv "a CSV file" | get-member -type NoteProperty).count
$Line = $_
if ($csvColumnCount -ne $CurrentLineCount)
{ $Line -Replace "," , "" }
else
{ $Line } ;
$CurrentLineCount++} |
Set-Content ($CurrentFile+".out")
Copy-Item ($CurrentFile+".out") $ReplaceCSVFile
If your intention is to check which rows of a CSV file are invalid then just use a simple split and count, something like so:
$csv = Get-Content 'your_file.csv'
$count = ($csv[0] -split ',').count
$csv | Select -Skip 1 | % {
if(($_ -split ',').count -eq $count) {
...do valid stuff
} else {
...do invalid stuff
}
}
For CSV checking purposes avoid CSV cmdlets because these will have a tendency to try and correct problems, for example:
$x = #"
a,b,c
1,2,3,4
"#
$x | ConvertFrom-Csv
> a b c
- - -
1 2 3
Also I think the flow of your code is a little confused. You trying to return the results of a pipeline to a variable called $CurrentFile whilst at the other end of that pipeline you are trying use the same variable as a file name for Set-Content.
If your CSV has quoted fields which could contain commas then a simple split will not work. If that is the case a better option would be to use a regex to break each line into columns which can then be counted. Something like this:
$re = '(?:^|,)(?:\"(?:[^\"]+|\"\")*\"|[^,]*)'
$csv = Get-Content 'your_file.csv'
$count = [regex]::matches($csv[0], $re).groups.count
$csv | Select -Skip 1 | % {
if([regex]::matches($_, $re).groups.count -eq $count) {
...do valid stuff
} else {
...do invalid stuff
}
}

Create a CSV with all AD users to import into Elastix

I'm working in a test environment with about 1000 users and I'm trying to create a CSV with the following headers to be used in Elastix: Display Name, User Extension, Secret, Tech.
The users currently do not have extensions assigned to them and random extensions would be fine. The secret will be "123456" for all of them. The Tech will be "Sip" for all of them.
Currently I have this, but I'm struggling to strip the name off each user in my loop:
$users = get-aduser -filter * | Select Name
$outpath = "C:\scripts\users.csv"
$outputArray =#()
"Display Name, User Extension, Secret, Tech"|out-file $outpath -Force
$ext = 1000
foreach($row in $users)
{
$outputArray += "," + $ext++ + "," + "123456" + "," + "Sip"
}
$outputArray | out-file $outpath -Force
Use can do this using the Select-Object cmdlet with 'calculated properties' and the Export-Csv cmdlet.
(Note: In my original answer I did not specify the script scope for the randomExtension variable when modified in an expression. When trying to fix, I found the solution here: How can I increase the value of a variable in an expression?
$outputPath = "C:\test\users.csv"
$script:randomExtension = 1000
get-aduser -filter * |
Select #{n='Display Name';e={$_.Name}},
#{n='User Extension';e={$script:randomExtension++; $script:randomExtension}},
#{n='Secret';e={'123456'}},
#{n='Tech';e={'Sip'}} |
Export-Csv -Path $outputPath -NoTypeInformation

How to update AD Info attribute to list groups user was deleted from?

I have this script that will only list a user's groups on the ISE screen where the data can be copied and pasted elsewhere, but I'm trying to get the group membership names written into the Telephone Notes tab (or Info field). I'm thinking next that these probably need to be turned into string values since I'm getting errors about multi properties not allowed. Here is what I've been trying, but I keep getting errors. Thanks
Import-Module ActiveDirectory
$Users= Import-csv "C:\Scripts\UsersSAM-DisplayName.csv"
ForEach ($User in $Users) {
$SamAccountName=$User.SamAccountName
$DisplayName=$User.DisplayName
$TableFormat= #{E={$_.Name};L="$($DisplayName) - $($SamAccountName)"}
Get-ADUser -Identity $SamAccountName -Properties MemberOf | % {$_.MemberOf } | % {Get-ADGroup -Identity $_ } | % { Set-ADUser -Identity $SamAccountName -add #{info="$_.name"}} | Select Name |
Format-Table $TableFormat }
I figured this out. What they wanted was to first write out a terminated user's groups, then remove those. I did it like this and this code includes the semi-colon so if the user comes back, all you need to do to add them back to all the groups is copy and paste those from the output stored in the Telephones Tab, Notes field. I've also used a trimmed down version of this to export a user's groups to speed up duplicating a user's groups so they match with others on the same team. Hope this helps someone.
Import-csv "$Terms" | % {
$user = Get-ADUser -LDAPFilter ("(sAMAccountName=" + $_.samaccountname + ")") -Properties samaccountname,enabled,name,memberof,distinguishedname,info
#Grab all user group names
$user | ForEach-Object {
$grps = $_.MemberOf | Get-ADGroup | ForEach-Object {$_.Name} | Sort-Object
$arec = $_.Name,$_.SamAccountName
$aline = ($grps -join ";")
#Add info to Notes field Telephone Tab
Get-ADPrincipalGroupMembership -Identity $user | %{
If ($_.SamAccountName -ne "Domain Users") {
$Userinfo=$user.info
Set-ADUser $User -replace #{info= "$Userinfo | $a | Terminated via automated process | $aline"}
#Remove User Groups Process in Telephones Tab Notes Field.
Remove-ADPrincipalGroupMembership -Identity $user -MemberOf $_.SamAccountName -Confirm:$false
(" "+ $a +" [" + $User.samaccountname + "], Removed from group [" + $_.samaccountname + "]. ") | Out-File -FilePath $ErrorLog -Append
}
}}}