Copy column of list to new column of same list in Sharepoint - sharepoint-2013

I want to copy the whole column values to a new column.
As a solution, I prepare a workflow:
SET FIELD TO VALUE and make the workflow start when item update
But, I have 16000+ rows and to manually update each one is not possible as of now.
I also tried using Microsoft Flow but no success.
Could anyone please suggest a way to achieve it.

I would suggest PowerShell for such 'migration' work. Script from here,the script need to be run in SharePoint server.
Add-PSSnapin Microsoft.SharePoint.Powershell -ErrorAction SilentlyContinue
#Parameters
$SiteURL = "http://siteurl/"
$listName = "list"
$web = Get-SPweb $SiteURL
#Use the Display Names
$CopyFromColumnName = "Description" #column copy source
$CopyToColumnName = "Desc" #destination column
#Get the List
$list = $web.lists[$ListName]
#Get all Items
$Items = $list.Items
ForEach ($Item in $items)
{
#copy data from one column to another
$item[$copyToColumnName] = $item[$copyFromColumnName]
#Do a system update to avoid Version and to Keep same metadata
$item.SystemUpdate($false)
}
For SharePoint online, refer this thread, replace the iterate logic as pageing.
$Query = New-Object Microsoft.SharePoint.Client.CamlQuery
$Query.ViewXml = "<View Scope='RecursiveAll'><Query><OrderBy><FieldRef Name='ID' Ascending='TRUE'/></OrderBy></Query><RowLimit Paged='TRUE'>$BatchSize</RowLimit></View>"
$Counter = 0
#Batch process list items - to mitigate list threshold issue on larger lists
Do {
#Get items from the list
$ListItems = $List.GetItems($Query)
$Ctx.Load($ListItems)
$Ctx.ExecuteQuery()
$Query.ListItemCollectionPosition = $ListItems.ListItemCollectionPosition
#Loop through each List item
ForEach($ListItem in $ListItems)
{
//to do copy field value
$Counter++
Write-Progress -PercentComplete ($Counter / ($List.ItemCount) * 100) -Activity "Processing Items $Counter of $($List.ItemCount)" -Status "Searching Unique Permissions in List Items of '$($List.Title)'"
}
} While ($Query.ListItemCollectionPosition -ne $null)

Related

How can I grab a user's logonworkstations list and remove all entries that match a csv listing

WorkstationList.csv has 3 separate columns with different names. Trying to use a column "retired" that has a list of retired logonworkstations names and match them to a users current list. If there is a match then delete from the users logonworkstation list.
$defaultWorkstationslist = Import-Csv -Path '[workstationList.csv]'
$olist = Get-Aduser $user-Properties LogonWorkstations | Select LogonWorkstations
$newlist = ''
foreach ($o in $olist){
foreach ($r in $defaultWorkstationslist.retired){
if ($o -ne $r){
$newlist += $o
} else {
continue
}
}
}
Set-ADUser $user -logonWorkstations $newlist
Output:
Set-ADUser : The format of the specified computer name is invalid
[redacted]:36 char:1
+ Set-ADUser $user-logonWorkstations $newlist
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : NotSpecified: (user:ADUser) [Set-ADUser], ADException
+ FullyQualifiedErrorId : ActiveDirectoryServer:1210,Microsoft.ActiveDirectory.Management.Commands.SetADUser
According to the Set-ADUser Docs for this specific parameter:
To specify more than one computer, create a single comma-separated list. You can identify a computer by using the Security Account Manager (SAM) account name (sAMAccountName) or the DNS host name of the computer. The SAM account name is the same as the NetBIOS name of the computer.
We can assume that, if the user has this property set, it would be a string with each computer comma separated (computer1,computer2...). Following that assumption, we can first test if the user has that property set, then split the value by comma and lastly filter each value against the $defaultWorkstationslist.retired array.
Important Note, this should work as long as the column Retired from your Csv has computer names using the SAM account name or NetBIOS name of the computer as stated in the docs.
$user = 'someuser'
$defaultWorkstationslist = Import-Csv -Path '[workstationList.csv]'
$aduser = Get-ADUser $user -Properties LogonWorkstations
# if this user has the attribute set
if($wsList = $aduser.LogonWorkstations) {
# split the string by comma and then use filtering technique to exclude those values that
# exists in the `$defaultWorkstationslist.retired` array.
$allowedList = ($wsList.Split(',').Where{ $_ -notin $defaultWorkstationslist.retired }) -join ','
Set-ADUser $user -LogonWorkstations $allowedList
}
For filtering we can use the .Where intrinsic method, where the current object in the pipeline is represented with $_ ($PSItem)
For testing if an element $wsList is contained in $defaultWorkstationslist.retired we can use Containment operators.

AWS glue delete all partitions

I defined several tables in AWS glue.
Over the past few weeks, I've had different issues with the table definition which I had to fix manually - I want to change column names, or types, or change the serialization lib. However, If i already have partitions created, the repairing of table doesn't change them, and so I have to delete all partitions manually and then repairing.
Is there a simple way to do this? Delete all partitions from an AWS Glue table?
I'm using aws batch-delete-partition CLI command, but it's syntax is tricky, and there are some limitations on the amount of partitions you can delete in one go, the whole thing is cumbersome...
For now, I found this command line solution, runinng aws glue batch-delete-partition iteratively for batches of 25 partitions using xargs
(here I am assuming there are max 1000 partitions):
aws glue get-partitions --database-name=<my-database> --table-name=<my-table> | jq -cr '[ { Values: .Partitions[].Values } ]' > partitions.json
seq 0 25 1000 | xargs -I _ bash -c "cat partitions.json | jq -c '.[_:_+25]'" | while read X; do aws glue batch-delete-partition --database-name=<my-database> --table-name=<my-table > --partitions-to-delete=$X; done
Hope it helps someone, but I'd prefer a more elegant solution
Using python3 with boto3 looks a little bit nicer. Albeit not by much :)
Unfortunately AWS doesn't provide a way to delete all partitions without batching 25 requests at a time. Note that this will only work for deleting the first page of partitions retrieved.
import boto3
glue_client = boto3.client("glue", "us-west-2")
def get_and_delete_partitions(database, table, batch=25):
partitions = glue_client.get_partitions(
DatabaseName=database,
TableName=table)["Partitions"]
for i in range(0, len(partitions), batch):
to_delete = [{k:v[k]} for k,v in zip(["Values"]*batch, partitions[i:i+batch])]
glue_client.batch_delete_partition(
DatabaseName=database,
TableName=table,
PartitionsToDelete=to_delete)
EDIT: To delete all partitions (beyond just the first page) using paginators makes it look cleaner.
import boto3
glue_client = boto3.client("glue", "us-west-2")
def delete_partitions(database, table, partitions, batch=25):
for i in range(0, len(partitions), batch):
to_delete = [{k:v[k]} for k,v in zip(["Values"]*batch, partitions[i:i+batch])]
glue_client.batch_delete_partition(
DatabaseName=database,
TableName=table,
PartitionsToDelete=to_delete)
def get_and_delete_partitions(database, table):
paginator = glue_client.get_paginator('get_partitions')
itr = paginator.paginate(DatabaseName=database, TableName=table)
for page in itr:
delete_partitions(database, table, page["Partitions"])
Here is a PowerShell version FWIW:
$database = 'your db name'
$table = 'your table name'
# Set the variables above
$batch_size = 25
Set-DefaultAWSRegion -Region eu-west-2
$partition_list = Get-GLUEPartitionList -DatabaseName $database -TableName $table
$selected_partitions = $partition_list
# Uncomment and edit predicate to select only certain partitions
# $selected_partitions = $partition_list | Where-Object {$_.Values[0] -gt '2020-07-20'}
$selected_values = $selected_partitions | Select-Object -Property Values
for ($i = 0; $i -lt $selected_values.Count; $i += $batch_size) {
$chunk = $selected_values[$i..($i + $batch_size - 1)]
Remove-GLUEPartitionBatch -DatabaseName $database -TableName $table -PartitionsToDelete $chunk -Force
}
# Now run `MSCK REPAIR TABLE db_name.table_name` to add the partitions again

Split Strings in a Value column with Powercli

This is what I wrote to get output with powercli;
Get-VM -name SERVERX | Get-Annotation -CustomAttribute "Last EMC vProxy Backup"|select #{N='VM';E={$_.AnnotatedEntity}},Value
This is the output
VM Value
-- -----
SERVERX Backup Server=networker01, Policy=vmbackup, Workflow=Linux_Test_Production, Action=Linux_Test_Production, JobId=1039978, StartTime=2018-10-31T00:00:27Z, EndTime=2018-10-31T00:12:45Z
SERVERX1 Backup Server=networker01, Policy=vmbackup, Workflow=Linux_Test_Production, Action=Linux_Test_Production, JobId=1226232, StartTime=2018-12-06T00:00:29Z, EndTime=2018-12-06T00:0...
SERVERX2 Backup Server=networker01, Policy=vmbackup, Workflow=Linux_Test_Production, Action=Linux_Test_Production, JobId=1226239, StartTime=2018-12-05T23:58:27Z, EndTime=2018-12-06T00:0...
But I would like retrieve only "starttime" and "endtime" values
Desired output is;
VM Value
-- -----
SERVERX StartTime=2018-10-31T00:00:27Z, EndTime=2018-10-31T00:12:45Z
SERVERX1 StartTime=2018-12-06T00:00:29Z, EndTime=2018-1206T00:11:14Z
SERVERX2 StartTime=2018-12-05T23:58:27Z, EndTime=2018-12-06T00:11:20Z
How can I get this output?
This would be better suited in Powershell forum as this is just data manipulation.
Providing your output is always the same number of commas then
$myannotation = Get-VM -name SERVERX | Get-Annotation -CustomAttribute "Last EMC
vProxy Backup"|select #{N='VM';E={$_.AnnotatedEntity}},Value
$table1 = #()
foreach($a in $myannotation)
$splitter = $a.value -split ','
$splitbackupstart = $splitter[5]
$splitbackupend = $splitter[6]
$row = '' | select vmname, backupstart, backupend
$row.vmname = $a.AnnotatedEntity # or .vm would have to try
$row.backupstart = $splitbackupstart
$row.backupend= $splitbackupend
$table1 += $row
}
$table1
Untested. If you format of the string is going to change over time then a regex to search for starttime will be better.

Rename files in Powershell with a reference file

Sorry for previous confusion...
I've spent several hours today trying to write a powershell script that will pull a client ID off a PDF from system #1 (example, Smith,John_H123_20171012.pdf where the client ID is the H#### value), then look it up in an Excel spreadsheet that contains the client ID in system 1 and system 2, then rename the file to the format needed for system 2 (xxx_0000000123_yyy.pdf).
One gotcha is that client # is 2-4 digits in system 2 and always preceeded by 0's.
Using Powershell and regular expressions.
This is the first part I am trying to use for my initial rename:
Get-ChildItem -Filter *.pdf | Foreach-Object{
$pattern = "_H(.*?)_2"
$OrionID = [regex]::Match($file, $pattern).Groups[1].value
Rename-Item -NewName $OrionID
}
It is not accepting "NewName" because it states it is an empty string. I have run:
Get-Variable | select name,value,Description
And new name shows up as a name but with no value. How can I pass the output from the Regex into the rename?
Run this code line by line in debugger, you will understand how this works.
#Starts an Excel process, you can see Excel.exe as background process
$processExcel = New-Object -com Excel.Application
#If you set it to $False you wont see whats going on on Excel App
$processExcel.visible = $True
$filePath="C:\somePath\file.xls"
#Open $filePath file
$Workbook=$processExcel.Workbooks.Open($filePath)
#Select sheet 1
$sheet = $Workbook.Worksheets.Item(1)
#Select sheet with name "Name of some sheet"
$sheetTwo = $Workbook.Worksheets.Item("Name of some sheet")
#This will store C1 text on the variable
$cellString = $sheet.cells.item(3,1).text
#This will set A4 with variable value
$sheet.cells.item(1,4) = $cellString
#Iterate through all the sheet
$lastUsedRow = $sheet.UsedRange.Rows.count
$LastUsedColumn = $sheet.UsedRange.Columns.count
for ($i = 1;$i -le $lastUsedRow; $i++){
for ($j = 1;$j -le $LastUsedColumn; $j++){
$otherString = $sheet.cells.item($i,$j).text
}
}
#Create new Workbook and add sheet to it
$newWorkBook = $processExcel.Workbooks.Add()
$newWorkBook.worksheets.add()
$newSheet = $newWorkBook.worksheets.item(1)
$newSheet.name="SomeName"
#Close the workbook, if you set $False it wont save any changes, same as close without save
$Workbook.close($True)
#$Workbook.SaveAs("C:\newPath\newFile.xls",56) #You can save as the sheet, 56 is format code, check it o internet
$newWorkBook.close($False)
#Closes Excel app
$processExcel.Quit()
#This code is to remove the Excel process from the OS, this does not always work.
[System.Runtime.Interopservices.Marshal]::ReleaseComObject($processExcel)
Remove-Variable processExcel
I ended up using a utility called "Bulk Rename Utility" and Excel. I can run the various renaming regex's through BRU and add the reference .txt file after some Excel formatting.

RegEx PowerShell match

I have the following website http://www.shazam.com/charts/top-100/australia which displays songs, I want to capture the songs using RegEx & PowerShell. The PowerShell code below is what I have so far:
$ie = New-Object -comObject InternetExplorer.Application
$ie.navigate('http://www.shazam.com/charts/top-100/australia')
Start-Sleep -Seconds 10
$null = $ie.Document.body.innerhtml -match 'data-chart-position="1"(.|\n)*data-track-title=.*content="(.*)"><a href(.|\n)*data-track-artist=\W\W>(.|\n)*<meta\scontent="(.*)"\sitemprop';$shazam01artist = $matches[5];$shazam01title = $matches[2]
data-chart-position
data-track-title
data-track-artist
Each of the songs listed have the 3 values (above) associated with each of them, I want to capture the Artist & Title for each song based on the different chart positions (numbers). So a regular expression to find the actual chart position, then the trailing Artist & Title.
If I run the RegEx separately for Artist & Title (code below), it finds them, however it only finds the first Artist & Title. I need to find the Artist & Title for each song based on the different chart position.
$null = $ie.Document.body.innerhtml -match 'data-track-artist=\W\W>(.|\n)*<meta\scontent="(.*)"\sitemprop';$shazam01artist = $matches[2]
$null = $ie.Document.body.innerhtml -match 'data-track-title=.*content="(.*)"><a href';$shazam01title = $matches[1]
$shazam01artist
$shazam01title
Using regex to parse partial HTML is an absolute nightmare, you might want to reconsider that approach.
Invoke-WebRequest returns a property called ParsedHtml, that contains a reference to a pre-parsed HTMLDocument object. Use that instead:
# Fetch the document
$Top100Response = Invoke-WebRequest -Uri 'http://www.shazam.com/charts/top-100/australia'
# Select all the "article" elements that contain charted tracks
$Top100Entries = $Top100Response.ParsedHtml.getElementsByTagName("article") |Where-Object {$_.className -eq 'ti__container'}
# Iterate over each article
$Top100 = foreach($Entry in $Top100Entries){
$Properties = #{
# Collect the chart position from the article element
Position = $Entry.getAttribute('data-chart-position',0)
}
# Iterate over the inner paragraphs containing the remaining details
$Entry.getElementsByTagName('p') |ForEach-Object {
if($_.className -eq 'ti__artist') {
# the ti__artist paragraph contains a META element that holds the artist name
$Properties['Artist'] = $_.getElementsByTagName('META').item(0).getAttribute('content',0)
} elseif ($_.className -eq 'ti__title') {
# the ti__title paragraph stores the title name directly in the content attribute
$Properties['Title'] = $_.getAttribute('content',0)
}
}
# Create a psobject based on the details we just collected
New-Object -TypeName psobject -Property $Properties
}
Now, let's see how Tay-Tay's doing down under:
PS C:\> $Top100 |Where-Object { $_.Artist -match "Taylor Swift" }
Position Title Artist
-------- ----- ------
42 Bad Blood Taylor Swift Feat. Kendrick Lamar
Sweet!