Renaming computers with a CSV file - powershell

I need some assistance as to how I can rename pcs in bulk with a powershell script and a csv file. I will need to achieve this via Kaseya (VSA) which manages our Windows devices. Here is how I am thinking of achieving this:
Filter all agents in VSA and export them in a CSV file.
In that CSV file there will be two columns; "currenthostname" & "newhostname"
I will insert the newhostname column and manually type in the hostnames
Upload the csv file with the newly added "newhostname" column
Kaseya will push the csv file out to all the hosts into the "C:\kworking" directory
I will need to assemble a script that imports the csv file and searches for the current hostname of the machine under the currenthostname column; if there is a match, then the machine will need to be renamed to the new hostname corresponding to the currenthostname column.
Step 6 is where I am having trouble and would like any insight anyone can provide. Here is what my script looks like so far:
$hostnames = Import-Csv "C:\kworking\hostnames.csv"
foreach ($hostname in $hostnames) {
$currentname = $hostname.oldName
$newname = $hostname.newName
$pcname = hostname
if ($pcname -match $currentname) {
Write-Host "Renaming computer from: $pcname to: $newname"
rename-computer -newname $newname
}
}

How long are your computer names? Max length is 63 characters, with only (a-z), (A-Z), number (0-9), and hyphen (-) characters permitted. No spaces, dots or number-only names.
The easiest way is to keep the names to 15 chars or less so you can be sure there are no dupes. Or use the -force parameter to accept whatever NETBIOS name it autogenerates (which you now have no record of, but it doesn't matter too much most of the time).
I'd also recommend including the -Restart parameter to keep it consistent. Naturally it won't restart if the command fails.

Related

Why does my powershell script loop not work when run, but when stepped through in debugger it works fine?

So I have the below script for a project at work:
# This script will look for a CSV in the script folder
# If found it will split the CSV based on a change in a column header
# It will then create seperate CSV files based on the column data
# get script directory and add it to a variable
Set-Location $PSScriptRoot
$baseDir = $PSScriptRoot
# get a list of csv file names
$csvfile = Get-ChildItem -Path $baseDir -Filter *.csv
# If multiple CSV files loop through all of them
foreach ($i in $csvfile) {
# Import and split the original csv
# Change the value after -Property to match the column header name of the column used to split on value change -
# Header names with spaces require surrounding quotes -
# This value will also be used to name the resulting CSV file
Import-Csv $i | Group-Object -Property "Submission ID" |
Foreach-Object {$path="Output\"+$_.name+".csv" ; $_.group |
Export-Csv -Path $path -NoTypeInformation}
# get the current time and date
$procdte = Get-Date -uformat "%m-%d-%Y %H %M %S"
# rename the original file so that it's not processed again
Rename-Item $i -NewName "Processed $procdte.txt"
}
# End processing loop
Important: some parts of this script are commented out - like the Rename-Item line is half-commented. Dunno why, think it's a stackoverflow markdown issue. It isn't like that in ISE
I tested it out with two csv files in the current directory. It's supposed to rename both files at the end to a .txt so they don't get processed again. When I just run the script, it misses the 2nd csv file. But when I step through it with debugger in ISE, it renames both files fine. What gives?
Ran powershell script, expecting both CSV files to be renamed, however it only renamed one of them. Thought there was an issue with the script, but when I run it in debug, it renames both files fine. Have managed to replicate multiple times.
Edit: to specify - this is not designed to work with two csv files specifically. It's supposed to work with one or more. I was just using two to test.

Exporting CSV in powershell to include the "$server" from a read-host entry

I wrote a powershell script to get a list of all installed software and version information for each of our servers. I'd like to be able to export it to a .csv file and name it after the $server name that was entered.
Export-CSV -path "C:\Scripts\Server_Audit\$server_Software_List.csv"
When I find that file in the folder, it just says .csv.
Do I need to declare that in another fashion so that it works?
An underscore is a valid part of a variable name, so it's trying to add $server_Software_List to the file path. One solution is to use $() in your string:
Export-CSV -path "C:\Scripts\Server_Audit\$($server)_Software_List.csv"

Powershell pattern matching

I have a requirement to create directories based on a numeric 9 digit with leading zeros primary key from an order entry database on a remote server.
Each morning a new directory should be created. The directory name will be the primary key number of the new customer. I already have the sql statement extracting the primary key information into a text file using BCP that preserves the leading zeros.
This file is transferred from the database server to the local directory where the folders need to be created. Using some PowerShell code that I think I found I am trying to create the folders from the text file that I have been modifying.
I need the leading zeros preserved in the folder name so I can reference back to the database later in the project. My problem is that when I run the PowerShell script, no folders are created. I think I have the problem isolated to the pattern definition, but don't understand what is wrong.
Input txt file example
001132884
001454596
001454602
001454605
001454606
001454601
001107119
001454600
001454608
PowerShell script
$folder="Customerdocuments"; # Directory to place the new folders in.
$txtFile="E:\dirtext.txt"; # File with list of new folder-names
$pattern="\d+.+"; # Pattern that lines must match
Get-Content $txtFile | %{
if($_ -match $pattern)
{
mkdir "$folder\$_";
}
}
I'm missing a clear question/error report.
Your pattern takes all digits (greedy) from input \d+
and requires at least one other (any) character .+ which isn't present in your sample file.
So your issue isn't related to leading zeroes.
Better specify exactly 9 digits and put that into a Where-object,
The path from $folder will be relative to the current folder and should be build using Join-Path
As mkdir is just a wrapper function for New-Item and it supports piped input I'd use it directly.
$folder="Customerdocuments"; # Directory to place the new folders in.
$txtFile="E:\dirtext.txt"; # File with list of new folder-names
$pattern="^\d{9}$" # Pattern that lines must match
Get-Content $txtFile | Where-Object {$_ -match $pattern}|
New-Item -Path {Join-Path $folder $_} -ItemType Directory | Out-Null
}

Strings and Test-Path Issues

I am working on a PowerCLI (VMware) script that will copy the VMX from the datastores for each VM. One of the initial issues was working with spaces in the VM name. After fixing that issue, there was another hurdle that I'm still struggling on. I am doing a Test-Path to check to make sure the datastore and folder where the VMX file resides can be reached before trying to copy the file. However, the Test-Path fails with the following message:
Set-Location : Cannot find drive. A drive with the name ''vmstore' does not exist.
The ultimate issue is the ' (single quote) just before vmstore being sent to the Test-Path cmdlet. But the output of the variable containing the full path doesn't contain that additional quote. Also when doing the Test-Path with the path entered in directly and using the single quotes, it works fine.
Here's the full script of getting the VMX file location and testing the path:
$gstrdatastorepath = "vmstore:\Cluster_Name\"
$lobjPrimaryDisk = Get-HardDisk -VM $VM | where {$_.name -EQ "Hard disk 1"} #looks for the first hard disk listed in VM definition. This is typically the primary source for the VMX file
$lstrDiskText = $lobjPrimaryDisk.filename #convert the filename to a string for manipulation.
#The string is typically as follows (without the quotes): "[datastore_name] folder_name/filename.vmdk
#Only the datastore_name and the folder_name are needed. The following now splits those from the vmdk file
$lstrDiskSplitInfo = $lstrDiskText.split("\/") #splits the text into two sections. First section is the primary information needed, the second is not used
#Now the datastore_name and the folder_name need to be split
$lstrDiskFolderSplitInfo = $lstrDiskSplitInfo[0] -split " ", 2 #splits the text into the datastore and folder name on the datastore. option 2 used in the event spaces are in VM name.
#Put the Disk and Folder information into separate variables
$lstrdatastorename = $lstrDiskFolderSplitInfo[0] -replace '[[\]]','' #removes the square brackets from the datastore name
$lstrfoldername = $lstrDiskFolderSplitInfo[1] #gets the folder name from the previous split
$completeDataStorePath = $gstrdatastorepath + $lstrdatastorename + "\" + $lstrfoldername #combines the information to return the full path of the VMX file
$completeVMXPathQuoted = "`'$completeDataStorePath`'" #put the path in a single quote for VM's with spaces in the name
The value of $completeVMXPathQuoted is 'vmstore:\Cluster_Name\Data_Store\VM_Name' where VM_Name may or may not contain spaces.
When doing the Test-Path, using the $completeVMXPathQuoted variable, it fails with the message mentioned above.
But when doing Test-Path -Path 'vmstore:\Cluster_Name\Data_Store\VM_Name' it works fine.
What am I missing? Where is that second single quote mark coming from?
Thank you in advance for any assistance.

How can I remove a number from a list of strings and find unique instances?

Our product consists of multiple WCF services that log some data to CSV files. Each service writes to its own set of files, where the files are named using a sequence number. For example:
Product.ServiceA1.csv
Product.ServiceA2.csv
Product.ServiceA3.csv
Product.ServiceB1.csv
Product.ServiceB2.csv
Product.ServiceB3.csv
The files are all written to a common folder, D:\Product\log.
I'm writing a script to process all the files for each service, and want to identify the results by service name, like so:
ServiceA: 25
ServiceB: 30
I've come up with the following PowerShell code to get me a list of the distinct service names, but was wondering if anyone has a better way.
# Get a list of all the file names; remove the 'Product' prefix and CSV file
# extension so we get just the base name.
$services = get-childitem $logFiles -Name | foreach { $_.Split(".")[1]}
# Remove all the sequence numbers and get a list of the unique names.
$services = [regex]::replace($services,'\d{1,3}','').split(" ") | get-unique
Thanks :)
You can try to do an "all-in-one" with regex.
$services = (Get-Childitem -Path $logFiles -Name) -replace '(?:.+?)([^\.0-9]+)(?:\d+)(?:\.csv)', '$1' | Get-Unique